# Always print this out before your assignment
sessionInfo()
R version 4.1.1 (2021-08-10)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 19043)

Matrix products: default

locale:
[1] LC_COLLATE=English_United States.1252  LC_CTYPE=English_United States.1252    LC_MONETARY=English_United States.1252
[4] LC_NUMERIC=C                           LC_TIME=English_United States.1252    

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] plotROC_2.2.1                glmnetUtils_1.1.8            glmnet_4.1-3                 Matrix_1.3-4                
 [5] randomForestExplainer_0.10.1 randomForest_4.6-14          urbnthemes_0.0.2             tidycensus_1.1              
 [9] usdata_0.2.0                 usmap_0.5.2.9999             urbnmapr_0.0.0.9002          corrplot_0.92               
[13] gdata_2.18.0                 scales_1.1.1.9000            tidyquant_1.0.3              quantmod_0.4.18             
[17] TTR_0.24.2                   PerformanceAnalytics_2.0.4   xts_0.12.1                   zoo_1.8-9                   
[21] plotly_4.10.0                viridis_0.6.2                viridisLite_0.4.0            pastecs_1.3.21              
[25] kableExtra_1.3.4             lubridate_1.8.0              rsample_0.1.1                ggthemes_4.2.4              
[29] ggrepel_0.9.1                here_1.0.1                   fs_1.5.1                     forcats_0.5.1               
[33] stringr_1.4.0                dplyr_1.0.7                  purrr_0.3.4                  readr_2.1.1                 
[37] tidyr_1.1.4                  tibble_3.1.6                 ggplot2_3.3.5                tidyverse_1.3.1             
[41] knitr_1.36                  

loaded via a namespace (and not attached):
  [1] readxl_1.3.1       uuid_1.0-3         backports_1.4.0    systemfonts_1.0.3  plyr_1.8.6         lazyeval_0.2.2    
  [7] splines_4.1.1      sp_1.4-6           listenv_0.8.0      digest_0.6.29      foreach_1.5.1      htmltools_0.5.2   
 [13] fansi_0.5.0        magrittr_2.0.1     tzdb_0.2.0         globals_0.14.0     modelr_0.1.8       extrafont_0.17    
 [19] extrafontdb_1.0    svglite_2.0.0      colorspace_2.0-2   rvest_1.0.2        rappdirs_0.3.3     haven_2.4.3       
 [25] xfun_0.28          rgdal_1.5-27       crayon_1.4.2       jsonlite_1.7.2     survival_3.2-11    tigris_1.5        
 [31] iterators_1.0.13   glue_1.5.1         gtable_0.3.0       webshot_0.5.2      Quandl_2.11.0      Rttf2pt1_1.3.9    
 [37] shape_1.4.6        DBI_1.1.1          GGally_2.1.2       Rcpp_1.0.7         units_0.7-2        foreign_0.8-81    
 [43] proxy_0.4-26       DT_0.20            htmlwidgets_1.5.4  httr_1.4.2         RColorBrewer_1.1-2 ellipsis_0.3.2    
 [49] farver_2.1.0       pkgconfig_2.0.3    reshape_0.8.8      sass_0.4.0         dbplyr_2.1.1       utf8_1.2.2        
 [55] labeling_0.4.2     tidyselect_1.1.1   rlang_0.4.12       munsell_0.5.0      cellranger_1.1.0   tools_4.1.1       
 [61] cli_3.1.0          generics_0.1.1     broom_0.7.10       evaluate_0.14      fastmap_1.1.0      yaml_2.2.1        
 [67] future_1.23.0      xml2_1.3.3         compiler_4.1.1     rstudioapi_0.13    curl_4.3.2         e1071_1.7-9       
 [73] reprex_2.0.1       bslib_0.3.1        stringi_1.7.6      lattice_0.20-44    classInt_0.4-3     vctrs_0.3.8       
 [79] pillar_1.6.4       lifecycle_1.0.1    furrr_0.2.3        jquerylib_0.1.4    data.table_1.14.2  maptools_1.1-2    
 [85] R6_2.5.1           KernSmooth_2.23-20 gridExtra_2.3      parallelly_1.29.0  codetools_0.2-18   boot_1.3-28       
 [91] gtools_3.9.2       assertthat_0.2.1   rprojroot_2.0.2    withr_2.4.3        parallel_4.1.1     hms_1.1.1         
 [97] quadprog_1.5-8     grid_4.1.1         class_7.3-19       rmarkdown_2.11     sf_1.0-4          
getwd()
[1] "C:/Users/Willis Admin/Google Drive/EMBA/8 - BUS_696/final_project/BROCODE_Final_Project"

# load all your libraries in this chunk 
library('tidyverse')
library("fs")
library('here')
library('dplyr')
library('tidyverse')
library('ggplot2')
library('ggrepel')
library('ggthemes')
library('forcats')
library('rsample')
library('lubridate')
library('ggthemes')
library('kableExtra')
library('pastecs')
library('viridis')
library('plotly')
library('tidyquant')
library('scales')
library("gdata")
library("corrplot")
library("urbnmapr")
library("usmap")
library("usdata")
library("tidycensus")
library("urbnthemes")
library("randomForest")
library("randomForestExplainer")
library('glmnet')
library('glmnetUtils')
library('plotROC')



#install.packages("remotes")
#remotes::install_github("UrbanInstitute/urbnthemes", build_vignettes = TRUE)

# note, do not run install.packages() inside a code chunk. install them in the console outside of a code chunk. 

Part 1 - Final Project Cleaning and Summary Statistics

1a) Loading data


#Reading the data in and doing minor initial cleaning in the function call
#Reproducible data analysis should avoid all automatic string to factor conversions.
#strip.white removes white space 
#na.strings is a substitution so all that have "" will = na
data <- read.csv(here::here("final_project", "donor_data.csv"),
                 stringsAsFactors = FALSE,
                 strip.white = TRUE,
                 na.strings = "")

1b) Fixing the wonky DOB & Data cleanup


#(Birthdate and Age, ID as a number)adding DOB (Age/Spouse Age) in years columns and adding two fields for assignment and number of children and number of degrees
dataclean <- data %>%
  mutate(Birthdate = ifelse(Birthdate == "0001-01-01", NA, Birthdate)) %>%
  mutate(Birthdate = mdy(Birthdate)) %>%
  mutate(Age = as.numeric(floor(interval(start= Birthdate, end=Sys.Date())/duration(n=1, unit="years")))) %>%
  mutate(Spouse.Birthdate = ifelse(Spouse.Birthdate == "0001-01-01", NA, Spouse.Birthdate)) %>%
  mutate(Spouse.Birthdate = mdy(Spouse.Birthdate)) %>%
  mutate(Spouse.Age = as.numeric(floor(interval(start= Spouse.Birthdate,
                                                end=Sys.Date())/duration(n=1, unit="years")))) %>%
  mutate(ID = as.numeric(ID)) %>% 
  mutate(Assignment_flag = ifelse(is.na(Assignment.Number), 0,1)) %>% 
  mutate( No_of_Children = ifelse(is.na(Child.1.ID),0,
                            ifelse(is.na(Child.2.ID),1,2)))%>%
 mutate(ID = as.numeric(ID)) %>% 
    mutate( nmb_degree = ifelse(is.na(Degree.Type.1),0,
                            ifelse(is.na(Degree.Type.2),1,2))) %>%
#conferral dates
  mutate(Conferral.Date.1 = ifelse(Conferral.Date.1 == "0001-01-01", NA, Conferral.Date.1)) %>%
  mutate(Conferral.Date.1 = mdy(Conferral.Date.1)) %>%
  mutate(Conferral.Date.1.Age = as.numeric(floor(interval(start= Conferral.Date.1, end=Sys.Date())/duration(n=1, unit="years")))) %>%
  
  mutate(Conferral.Date.2 = ifelse(Conferral.Date.2 == "0001-01-01", NA, Conferral.Date.2)) %>%
  mutate(Conferral.Date.2 = mdy(Conferral.Date.2)) %>%
  mutate(Conferral.Date.2.Age = as.numeric(floor(interval(start= Conferral.Date.2, end=Sys.Date())/duration(n=1, unit="years")))) %>%
  
  mutate(Last.Contact.By.Anyone = ifelse(Last.Contact.By.Anyone == "0001-01-01", NA, Last.Contact.By.Anyone)) %>%
  mutate(Last.Contact.By.Anyone = mdy(Last.Contact.By.Anyone)) %>%
  mutate(Last.Contact.Age = as.numeric(floor(interval(start= Last.Contact.By.Anyone, end=Sys.Date())/duration(n=1, unit="years")))) %>%
  
 mutate(HH.First.Gift.Date = ifelse(HH.First.Gift.Date == "0001-01-01", NA, HH.First.Gift.Date)) %>%
  mutate(HH.First.Gift.Date = mdy(HH.First.Gift.Date)) %>%
mutate(HH.First.Gift.Age = as.numeric(floor(interval(start= HH.First.Gift.Date, end=Sys.Date())/duration(n=1, unit="years")))) %>% 
#major gift 
  mutate(major_gifter = ifelse(Lifetime.Giving > 50000, 1,0) %>% factor(., levels = c("0","1"))) %>%
#splitting up the age into ranges and creating category for easy visualization 
  mutate(age_range = 
    ifelse(Age %in% 10:19, "10 < 20 years old",
    ifelse(Age %in% 20:29, "20 < 30 years old", 
    ifelse(Age %in% 30:39, "30 < 40 years old",
    ifelse(Age %in% 40:49, "40 < 50 years old",
    ifelse(Age %in% 50:59, "50 < 60 years old",
    ifelse(Age %in% 60:69, "60 < 70 years old",
    ifelse(Age %in% 70:79, "70 < 80 years old",
    ifelse(Age %in% 80:89, "80 < 90 years old",
    ifelse(Age %in% 90:120, "90+ years old",
    NA)))))))))) %>%
#creating a region column using the county data and the OMB MSA (Metropolitan Statistical Area) definitions
    ifelse(County == "San Luis Obispo" & State == "CA", "So Cal",
    ifelse(County == "San Bernardino" & State == "CA", "So Cal",
    ifelse(County == "Santa Barbara" & State == "CA", "So Cal",
    ifelse(County == "Ventura" & State == "CA", "So Cal",
    ifelse(County == "Los Angeles" & State == "CA", "So Cal",
    ifelse(County == "Orange" & State == "CA", "So Cal",
    ifelse(County == "Riverside" & State == "CA", "So Cal",
    ifelse(County == "San Diego" & State == "CA", "So Cal",
    ifelse(County == "Imperial" & State == "CA", "So Cal",
    ifelse(County == "King" & State == "WA", "Seattle",
    ifelse(County == "Snohomish" & State == "WA", "Seattle",
    ifelse(County == "Pierce" & State == "WA", "Seattle",
    ifelse(County == "Clackamas" & State == "OR", "Portland",
    ifelse(County == "Columbia" & State == "OR", "Portland",
    ifelse(County == "Multnomah" & State == "OR", "Portland",
    ifelse(County == "Washington" & State == "OR", "Portland",
    ifelse(County == "Yamhill" & State == "OR", "Portland",
    ifelse(County == "Clark" & State == "WA", "Portland",
    ifelse(County == "Skamania" & State == "WA", "Portland",
    ifelse(County == "Denver" & State == "CO", "Denver",
    ifelse(County == "Arapahoe" & State == "CO", "Denver",
    ifelse(County == "Jefferson" & State == "CO", "Denver",
    ifelse(County == "Adams" & State == "CO", "Denver",
    ifelse(County == "Douglas" & State == "CO", "Denver",
    ifelse(County == "Broomfield" & State == "CO", "Denver",    
    ifelse(County == "Elbert" & State == "CO", "Denver",
    ifelse(County == "Park" & State == "CO", "Denver",
    ifelse(County == "Clear Creek" & State == "CO", "Denver",
    ifelse(County == "Alameda" & State == "CA", "Bay Area",
    ifelse(County == "Contra Costa" & State == "CA", "Bay Area",
    ifelse(County == "Marin" & State == "CA", "Bay Area",
    ifelse(County == "Monterey" & State == "CA", "Bay Area",
    ifelse(County == "Napa" & State == "CA", "Bay Area",
    ifelse(County == "San Benito" & State == "CA", "Bay Area",
    ifelse(County == "San Francisco" & State == "CA", "Bay Area",
    ifelse(County == "San Mateo" & State == "CA", "Bay Area",
    ifelse(County == "Santa Clara" & State == "CA", "Bay Area",
    ifelse(County == "Santa Cruz" & State == "CA", "Bay Area",
    ifelse(County == "Solano" & State == "CA", "Bay Area",
    ifelse(County == "Sonoma" & State == "CA", "Bay Area",
           NA)))))))))))))))))))))))))))))))))))))))))) %>%
  mutate(region = 
    ifelse(County == "Kings" & State == "NY", "New York",
    ifelse(County == "Queens" & State == "NY", "New York",
    ifelse(County == "New York" & State == "NY", "New York",
    ifelse(County == "Bronx" & State == "NY", "New York",
    ifelse(County == "Richmond" & State == "NY", "New York",
    ifelse(County == "Westchester" & State == "NY", "New York",
    ifelse(County == "Bergen" & State == "NY", "New York",
    ifelse(County == "Hudson" & State == "NY", "New York",
    ifelse(County == "Passaic" & State == "NY", "New York",
    ifelse(County == "Putnam" & State == "NY", "New York",
    ifelse(County == "Rockland" & State == "NY", "New York",
    ifelse(County == "Suffolk" & State == "NY", "New York",
    ifelse(County == "Nassau" & State == "NY", "New York",
    ifelse(County == "Middlesex" & State == "NJ", "New York",
    ifelse(County == "Monmouth" & State == "NJ", "New York",
    ifelse(County == "Ocean" & State == "NJ", "New York",
    ifelse(County == "Somerset" & State == "NJ", "New York",
    ifelse(County == "Essex" & State == "NJ", "New York",
    ifelse(County == "Union" & State == "NJ", "New York",
    ifelse(County == "Morris" & State == "NJ", "New York",
    ifelse(County == "Sussex" & State == "NJ", "New York",
    ifelse(County == "Hunterdon" & State == "NJ", "New York",
    ifelse(County == "Pike" & State == "NJ", "New York",
    region)))))))))))))))))))))))) %>%

# code nor cal region as all others in CA not already defined
  mutate(region = 
    ifelse(State == "CA" & is.na(region) == TRUE, "Nor Cal", region))





#Initial Removal of Columns that provide no benefit 

dataclean <- subset(dataclean,select = -c(Assignment.Number
                                                    ,Assignment.has.Historical.Mngr
                                                    ,Suffix
                                                    ,Assignment.Date
                                                    ,Assignment.Manager
                                                    ,Assignment.Role
                                                    ,Assignment.Title
                                                    ,Assignment.Status
                                                    ,Strategy
                                                    ,Progress.Level
                                                    ,Assignment.Group
                                                    ,Assignment.Category
                                                    ,Funding.Method
                                                        ,Expected.Book.Date
                                                        ,Qualification.Amount
                                                        ,Expected.Book.Amount
                                                        ,Expected.Book.Date
                                                        ,Hard.Gift.Total
                                                        ,Soft.Credit.Total
                                                        ,Total.Assignment.Gifts
                                                        ,No.of.Pledges
                                                        ,Proposal..
                                                        ,Proposal.Notes
                                                        ,HH.Life.Spouse.Credit
                                                        ,Last.Contact.By.Manager
                                                        ,X..of.Contacts.By.Manager
                                                        ,DonorSearch.Range
                                                        ,iWave.Range
                                                        ,WealthEngine.Range
                                                        ,Philanthropic.Commitments
                                                        ))
#cleaning up zip codes removing -4 after 
dataclean$Zip <- gsub(dataclean$Zip, pattern="-.*", replacement = "")

#adding zip code data and column 
zip <- read.csv(here::here("final_project", "Salary_Zipcode.csv"),
                 stringsAsFactors = FALSE,
                 strip.white = TRUE,
                 na.strings = "")
dataclean <-dataclean %>%
    mutate(zipcode_slry = VLOOKUP(Zip, zip, NAME, S1902_C03_002E)) %>%
#slry range 
  mutate(zipslry_range = 
    ifelse(zipcode_slry %in% 10000:89999, "90K-99K",
    ifelse(zipcode_slry %in% 90000:99999, "90K-99K",
    ifelse(zipcode_slry %in% 100000:149999, "100K-149K", 
    ifelse(zipcode_slry %in% 150000:199999, "150K-199K",
    ifelse(zipcode_slry %in% 200000:249999, "200K-249K",
    ifelse(zipcode_slry %in% 250000:299999, "250K-299K",
    ifelse(zipcode_slry %in% 300000:349999, "300K-349K",
    ifelse(zipcode_slry %in% 350000:399999, "350K-399K",
    ifelse(zipcode_slry %in% 400000:499999, "400K-499K",
    ifelse(zipcode_slry %in% 500000:999999, "500K-999K",
    NA)))))))))))

sum(is.na(dataclean$zipcode_slry))
[1] 62347
#converting married Y and N to 1 and 0 
dataclean <- dataclean %>%
      mutate(Married_simple = ifelse(Married == "N",0,1))


dataclean <- dataclean %>% 
  mutate(hh.lifetime.giving_fct = as.factor(HH.Lifetime.Giving)) %>%
  mutate(HH.Lifetime.Giving.Plus = log(HH.Lifetime.Giving + 1)) %>% 
  mutate(Lifetime.Giving.Plus = log(Lifetime.Giving + 1)) %>% 
  mutate(average_yearly_donation = (HH.Total.Gifts.FY20.21+HH.Total.Gifts.FY19.20+HH.Total.Gifts.FY18.19+HH.Total.Gifts.FY17.18+HH.Total.Gifts.FY16.17)/5)

#adding scholarship data (y/n)
schlr <- read.csv(here::here("final_project", "scholarship.csv"),
                 stringsAsFactors = FALSE,
                 strip.white = TRUE,
                 na.strings = "")

#adding scholarship column
dataclean <-dataclean %>%
    mutate(scholarship = VLOOKUP(ID, schlr, ID, SCHOLARSHIP)) 

#replacing NA with 0 
 dataclean$scholarship <- replace_na(dataclean$scholarship,'0')
 
#replacing Y with 1 
dataclean$scholarship<-ifelse(dataclean$scholarship=="Y",1,0)

#checking how many are N
table(dataclean$scholarship)

     0      1 
295264  27962 
#checking and deleting scholarship column 
class(dataclean$schlr_fct)
[1] "NULL"
dataclean = subset(dataclean, select = -c(scholarship))
  
#checking for duplicates N >1 indicates a records values are in the file twice 
dataclean %>% group_by(ID) %>% count() %>% arrange(desc(n))

#removing duplicated records
dataclean <- unique(dataclean)

#Verifying n = 1 no ID with multiple records cleaned of dupes
dataclean %>% group_by(ID) %>% count() %>% arrange(desc(n))
NA

1d Creating many many factor variables


dataclean <- 
  dataclean %>% 
  #SEX
  mutate(sex_fct = 
           fct_explicit_na(Sex),
sex_simple = 
    fct_lump_n(Sex, n = 4),
#MARRIED
married_fct = 
           fct_explicit_na(Married),
  #DONOR SEGMENT
  donorseg_fct = 
           fct_explicit_na(Donor.Segment),
         donorseg_simple = 
           fct_lump_n(Donor.Segment, n = 4),
  #CONTACT RULE
         contact_fct = 
           fct_explicit_na(Contact.Rules),
         contact_simple = 
           fct_lump_n(Contact.Rules, n = 4),
  #SPOUSE MAIL
         spomail_fct = 
           fct_explicit_na(Spouse.Mail.Rules),
         spomail_simple = 
           fct_lump_n(Spouse.Mail.Rules, n = 4),
  #JOB TITLE
         jobtitle_fct = 
           fct_explicit_na(Job.Title),
         jobtitle_simple = 
           fct_lump_n(Job.Title, n = 5),
  #DEGREE TYPE 1
         deg1_fct = 
           fct_explicit_na(Degree.Type.1),
         deg1_simple = 
           fct_lump_n(Degree.Type.1, n = 5),
  #DEGREE TYPE 2
         deg2_fct = 
           fct_explicit_na(Degree.Type.2),
         deg2_simple = 
           fct_lump_n(Degree.Type.2, n = 5),
  #MAJOR 1
         maj1_fct = 
           fct_explicit_na(Major.1),
         maj1_simple = 
           fct_lump_n(Major.1, n = 5),
  #MAJOR 2
         maj2_fct = 
           fct_explicit_na(Major.2),
         maj2_simple = 
           fct_lump_n(Major.2, n = 5),
  #MINOR 1
         min1_fct = 
           fct_explicit_na(Minor.1),
         min1_simple = 
           fct_lump_n(Minor.1, n = 5),
  #MINOR 2
         min2_fct = 
           fct_explicit_na(Minor.2),
         min2_simple = 
           fct_lump_n(Minor.2, n = 5),
  #SCHOOL 1
         school1_fct = 
           fct_explicit_na(School.1),
         school1_simple = 
           fct_lump_n(School.1, n = 5),
  #SCHOOL 2
         school2_fct = 
           fct_explicit_na(School.2),
         school2_simple = 
           fct_lump_n(School.2, n = 5),
  #INSTITUTION TYPE
         insttype_fct = 
           fct_explicit_na(Institution.Type),
         insttype_simple = 
           fct_lump_n(Institution.Type, n = 5),
  #EXTRACURRICULAR
         extra_fct = 
           fct_explicit_na(Extracurricular),
         extra_simple = 
           fct_lump_n(Extracurricular, n = 5),
  #HH FIRST GIFT FUND
         hhfirstgift_fct = 
           fct_explicit_na(HH.First.Gift.Fund),
         hhfirstgift_simple = 
           fct_lump_n(HH.First.Gift.Fund, n = 5),
#CHILD 1 ENROLL STATUS
         ch1_enroll_fct = 
           fct_explicit_na(Child.1.Enroll.Status),
         ch1_enroll_simple = 
           fct_lump_n(Child.1.Enroll.Status, n = 4),
#CHILD 1 MAJOR
         ch1_maj_fct = 
           fct_explicit_na(Child.1.Major),
         ch1_maj_simple = 
           fct_lump_n(Child.1.Major, n = 4),
#CHILD 1 MINOR
         ch1_min_fct = 
           fct_explicit_na(Child.1.Minor),
         ch1_min_simple = 
           fct_lump_n(Child.1.Minor, n = 4),
#CHILD 1 SCHOOL
         ch1_school_fct = 
           fct_explicit_na(Child.1.School),
         ch1_school_simple = 
           fct_lump_n(Child.1.School, n = 4),
#CHILD 1 FEEDER
         ch1_feeder_fct = 
           fct_explicit_na(Child.1.Feeder.School),
         ch1_feeder_simple = 
           fct_lump_n(Child.1.Feeder.School, n = 4),
#CHILD 2 ENROLL STATUS
         ch1_enroll_fct = 
           fct_explicit_na(Child.2.Enroll.Status),
         ch2_enroll_simple = 
           fct_lump_n(Child.2.Enroll.Status, n = 4),
         ch2_maj_fct = 
         ch2_maj_simple = 
           fct_lump_n(Child.2.Major, n = 4),
#CHILD 2 MINOR
         ch2_min_fct = 
           fct_explicit_na(Child.2.Minor),
         ch2_min_simple = 
           fct_lump_n(Child.2.Minor, n = 4),
#CHILD 2 SCHOOL
         ch2_school_fct = 
           fct_explicit_na(Child.2.School),
         ch2_school_simple = 
           fct_lump_n(Child.2.School, n = 4),
#CHILD 2 FEEDER
         ch2_feeder_fct = 
           fct_explicit_na(Child.2.Feeder.School),
         ch2_feeder_simple = 
           fct_lump_n(Child.2.Feeder.School, n = 4),
#Region 
         region_fct = 
           fct_explicit_na(region),
         region_simple = 
           fct_lump_n(region, n = 5),
#Age
         age_range_fct = 
           fct_explicit_na(age_range),
    )

    



#checking to see if its a factor
#class(dataclean$sex_fct)
#class(dataclean$donorseg_fct)
#class(dataclean$contact_fct)
#class(dataclean$spomail_fct)

#checking levels
#levels(dataclean$sex_simple)
#levels(dataclean$donorseg_simple)
#levels(dataclean$contact_simple)
#levels(dataclean$spomail_simple)
#levels(dataclean$hhfirstgift_simple)

#creating a table against Sex column 
#table(dataclean$sex_fct, dataclean$sex_simple)

Part 2 - Summary Statistics

Region Analysis

#grouping by region and analyzing 

dataclean %>%
  filter(HH.Lifetime.Giving != 0)%>% #filtering out the 0s per our presentation and recommendations 
  group_by(region) %>%
  summarise(Count = length(region),
            median_total_giv = median(HH.Lifetime.Giving)) %>%
  arrange(-Count) %>%
  filter(Count >= 100) %>%
  mutate(median_total_giv = dollar(median_total_giv)) %>%
  kable(col.names = c("Region", "Count", "Median HH Lifetime Giving"), align=rep('c', 3)) %>%
  kable_styling(bootstrap_options = c("striped", "hover"),
                full_width = F)
Region Count Median HH Lifetime Giving
So Cal 49438 $100
NA 28462 $77
Bay Area 6046 $100
Nor Cal 2892 $100
Seattle 1753 $100
Portland 902 $100
Denver 802 $75
New York 731 $170
NA

DonorSegment Analysis

#grouping by donorsegment and analyzing 
  dataclean %>%
  filter(HH.Lifetime.Giving != 0)%>% #filtering 0s and adding median per
  group_by(Donor.Segment) %>%
  summarise(Count = length(Donor.Segment),
            median_total_giv = median(HH.Lifetime.Giving)) %>%
  arrange(-Count) %>%
  filter(Count >= 100) %>%
  #added scales package to have the values show in dollar 
  mutate(median_total_giv = (dollar(median_total_giv))) %>%
  kable(col.names = c("Donor Segment", "Count", "Median HH Lifetime Giving"), align=rep('c', 3)) %>%
  kable_styling(bootstrap_options = c("striped", "hover"),
                full_width = F)
Donor Segment Count Median HH Lifetime Giving
Lost Donor 69718 $85.00
Lapsed Donor 11193 $130.83
Current Donor 5603 $637.50
Lapsing Donor 3862 $250.00
At-Risk Donor 650 $750.00
NA
NA

First gift size analysis


dataclean %>%
  filter(HH.Lifetime.Giving != 0)
  aq <- quantile(dataclean$HH.First.Gift.Amount, probs = c(.25,.50,.75,.9,.99), na.rm = TRUE)

aq <- as.data.frame(aq)

aq$aq <- dollar(aq$aq)

aq %>%
  kable(col.names = "Quantile") %>%
  kable_styling(bootstrap_options = c("striped", "hover"),
                full_width = F)
Quantile
25% $0.00
50% $0.00
75% $0.00
90% $40.00
99% $1,910.06
NA
NA

Consecutive giving

#consecutive years of giving 
dataclean %>%
  filter(Max.Consec.Fiscal.Years > 0) %>%
  ggplot(aes(Max.Consec.Fiscal.Years)) + geom_histogram(fill = "#002845", bins = 20) + 
  theme_economist_white() +
  ggtitle("Consecutive Years of Giving Distribution") + 
  xlab(NULL) + ylab(NULL) + scale_x_continuous(breaks = seq(0,120,2)) +
  scale_y_continuous(breaks = seq(0,10000000,5000)) 

NA
NA
NA

Lifetime giving based on number of children

dataclean %>%
  filter(HH.Lifetime.Giving <= 10000) %>%
  filter(HH.Lifetime.Giving > 0) %>%
  mutate(`No_of_Children` = as.factor(`No_of_Children`)) %>%
  ggplot(aes(HH.Lifetime.Giving, fill = `No_of_Children`)) + geom_histogram(bins = 30) + theme_economist_white() +
  xlab(NULL) + ylab(NULL) + scale_x_continuous(breaks = seq(0,100000,1000)) +
  scale_y_continuous(breaks = seq(0,100000000,5000)) +
  ggtitle("Giving distribution and number of children")+ 
  scale_fill_manual(values=c("#002845", "#00cfcc", "#ff9973"))

NA
NA
NA

Mean, Median, and Count of Giving in Age Ranges


age_range_giving <- dataclean %>%
  group_by(age_range) %>%
  summarise(avg_giving = mean(HH.Lifetime.Giving, na.rm = TRUE),
            med_giving = median(HH.Lifetime.Giving, na.rm = TRUE),
            amount_of_people_in_age_range = n())


glimpse(age_range_giving)
Rows: 10
Columns: 4
$ age_range                     <chr> "10 < 20 years old", "20 < 30 years old", "30 < 40 years old", "40 < 50 years old~
$ avg_giving                    <dbl> 0.4501597, 28.2527107, 386.5961310, 810.4033032, 2778.4964811, 5400.1138522, 1156~
$ med_giving                    <dbl> 0, 0, 0, 0, 0, 0, 0, 10, 15, 0
$ amount_of_people_in_age_range <int> 3944, 24569, 21021, 16829, 20742, 18231, 12204, 5951, 6638, 192871

Plotting average giving by age range


age_range_giving <-
  age_range_giving %>%
  mutate(age_range = factor(age_range))

ggplot(age_range_giving, aes(age_range, avg_giving)) +
  geom_bar(stat = "identity")+
  theme(axis.text.x = element_text(angle=45,
                                        hjust=1)) + labs(x = "Age Range", y = "Average Giving") +
      ggtitle("Average Giving Compared Across Age Ranges")

NA
NA

Count of donors based on age range (another way to look at it)


ggplot(dataclean, 
       aes(age_range)) + 
       geom_bar() + 
       theme(axis.text.x = element_text(angle=45,
                                        hjust=1)) + 
  labs(title = "Count of Age Ranges", x = "", y = "")

NA
NA

Boxplot of the Age Ranges Against the Lifetime Giving Amounts with a log scale applied - the reason we applied log scale is to resolve issues with visualizations that skew towards large values in our dataset.

THIS CHUCNK WOULD NOT RUN ON FINAL COMPILATION. IT CLEARLY RAN DURING THE PREP OF OUR POWERPOINT PRESENTATION

2d) Splitting by age and gender



#creating boxplots 
dataclean %>% 
  filter(Age < 100) %>% #removing the weird outliers that are over 100 
  filter(Sex %in% c("M", "F")) %>%
  ggplot(aes(Sex, Age)) + 
  geom_boxplot() + 
  theme_economist() + 
  ggtitle("Ages of Donors Based on Gender") + 
  xlab(NULL) + ylab(NULL)

NA
NA

Giving by gender


#remove NAs U X

dataclean2 <- dataclean %>%
  filter(Sex %in% c("M", "F")) 

q <- ggplot(dataclean2) 
q + stat_summary_bin(
  aes(y = HH.Lifetime.Giving, x = Sex), 
  fun.y = "mean", geom = "bar") 

  
summary(dataclean$sex_simple)
     F      M      U      X   NA's 
120781 108190   3683      7  90339 

Mean age by gender

#breakdown of sexs 
tally(group_by(dataclean, Sex))

summarize(group_by(dataclean, Sex), 
          avg_giving = mean(HH.Lifetime.Giving, na.rm = TRUE),
          avg_age = mean(Age, na.rm = TRUE),
          med_age = median(Age, na.rm = TRUE))

#grouping by sex and age range for slides 
tally(group_by(dataclean, Sex, age_range))
NA
NA
NA

2e) Distribution of people in the states that they live.


  dataclean %>%
  mutate(State = ifelse(State == " ", "NA", State)) %>%
  filter(State != "NA") %>%
  group_by(State) %>%
  summarise(Count = length(State)) %>%
  filter(Count > 800) %>%
  arrange(-Count) %>%
  kable(col.names = c("Donor's State", "Count")) %>%
  kable_styling(bootstrap_options = c("condensed"),
                full_width = F)
Donor's State Count
CA 176487
WA 7957
TX 7266
NY 5659
CO 5073
AZ 4925
OR 4612
FL 4111
IL 3681
HI 3394
PA 2904
OH 2754
NV 2715
MI 2523
MA 2473
NJ 2311
VA 2158
NC 2085
GA 2044
MO 1889
MN 1732
MD 1488
TN 1443
IN 1417
CT 1380
WI 1330
UT 1173
OK 1151
AL 1120
LA 1110
ID 1096
SC 1076
KY 1032
KS 1027
NM 981
IA 880
NA
NA

2f) Looking at all donors first gift amount. 75% made a first gift of <100.


 no_non_donors <- dataclean %>%
  filter(Lifetime.Giving != 0)
  
nd <- quantile(no_non_donors$HH.First.Gift.Amount, probs = c(.25,.50,.75,.9,.99), na.rm = TRUE)

nd <- as.data.frame(nd)

nd %>%
  kable(col.names = "Quantile") %>%
  kable_styling(bootstrap_options = c("striped", "hover"),
Quantile
25% 3.8
50% 25.0
75% 100.0
90% 500.0
99% 15000.0
NA
NA
NA
NA
p <- dataclean %>%
  ggplot(aes(Age)) + geom_histogram(bins=30, fill = "blue") + theme_economist_white() +
  ggtitle("Overall Donor Age Distribution") + 
  xlab(NULL) + ylab(NULL) + scale_x_continuous(breaks = seq(5,100,by = 20)) +
  scale_y_continuous(breaks = seq(20,100,by = 20)) + xlim(c(20,100))
Scale for 'x' is already present. Adding another scale for 'x', which will replace the existing scale.
ggplotly(p)
  
p


ggplot(data = dataclean, aes(x = Age)) + geom_histogram(fill ="blue")+ xlim(c(20,100))
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

NA
NA
NA

Another Histogram


dataclean %>%
  filter(Age >= 10) %>%
  filter(Age <= 90) %>%
  ggplot(aes(Age)) + geom_histogram(fill = "#002845", bins = 20) + theme_economist_white() +
  ggtitle("Overall Donor Age Distribution") + 
  xlab(NULL) + ylab(NULL) + scale_x_continuous(breaks = seq(0,120,5)) +
  scale_y_continuous(breaks = seq(0,10000000,2000)) 

Age distribution by gender

#Age Gender filtered out below 15 and above 90 - also removed U X the weird values 
dataclean %>%
  filter(Age >= 15) %>%
  filter(Age <= 90) %>%
  mutate(Sex = as.factor(Sex)) %>%
  filter(Sex != "U") %>%
  filter(Sex != "X") %>%
  ggplot(aes(Age, fill = Sex)) + geom_histogram(bins = 25) + theme_economist_white() +
  ggtitle("Age Distribution by Gender") + 
  xlab(NULL) + ylab(NULL) + scale_x_continuous(breaks = seq(0,120,10)) +
  scale_y_continuous(breaks = seq(0,50000,2000)) + scale_fill_manual(values=c("#ff9973", "#00cfcc"))

Donor age distribution by marital status

#Age Marital Status
dataclean %>%
  filter(Age >= 20) %>%
  filter(Age <= 85) %>%
  ggplot(aes(Age, fill = Married)) + geom_histogram(bins = 25) + theme_economist_white() +
  ggtitle("Overall Donor Age Distribution by Marital Status") + 
  xlab(NULL) + ylab(NULL) + scale_x_continuous(breaks = seq(0,120,5)) +
  scale_y_continuous(breaks = seq(0,50000,2000)) + scale_fill_manual(values=c("#ff9973", "#00cfcc"))

Mapping

#add county after county name in order to use Urbnmapr

dataclean <- dataclean %>%
  mutate(County =
      ifelse(is.na(County) == TRUE, County, paste0(County, " County"))) 
    
dc_state_county <- dataclean %>%
  mutate(polyname =
      ifelse(is.na(County) == TRUE, County, paste0(State, ",",County)))

dc_state_county2 <- fips_codes %>%
  mutate(polyname = paste0(state, ",",county)) %>% 
  mutate(county_fips = paste0(state_code,county_code))

#Bring in the FIPS data to our data set since UrbnMapr uses FIPS

countymap_data <- left_join(dc_state_county, dc_state_county2, by = "polyname")


spatial_data <- left_join(get_urbn_map(map = "counties", sf = TRUE),
                          countymap_data,
                          by = "county_fips")
old-style crs object detected; please recreate object with a recent sf::st_crs()
# plot maps

ggplot() +
  geom_sf(spatial_data,
          mapping = aes(fill = HH.Lifetime.Giving),
          color = "#ffffff", size = 0.50) +
  labs(fill = "Household Lifetime Giving")


county_sf <- get_urbn_map(map = "counties", sf = TRUE)

county_sf %>% 
  left_join(countymap_data, by = "county_fips") %>% 
  ggplot() +
  geom_sf(mapping = aes(fill = HH.Lifetime.Giving),
          color = "#ffffff", size = 0.25) +
  theme_economist_white() +
  scale_fill_gradient(low = ("lightblue"),high = ("blue"),labels = scales::dollar) +
  labs(fill = "Household Lifetime Giving") +
  coord_sf(datum = NA)
old-style crs object detected; please recreate object with a recent sf::st_crs()

spatial_data %>% 
    filter(state_name.x == "California") %>%
    filter(HH.Lifetime.Giving != 0)%>%
    filter(HH.Lifetime.Giving %in% (100:1500000)) %>% 
  ggplot() +
    geom_sf(mapping = aes(fill = log(HH.Lifetime.Giving),na.rm=TRUE),
                 color = "#666666", size = 0.10) +
     coord_sf(datum = NA) +
    scale_fill_gradient(low = ("lightblue"),high = ("blue"),labels = scales::dollar) +
  labs(fill = "Household Lifetime Giving")


spatial_data %>% 
    filter(state_name.x == "Florida") %>%
    filter(HH.Lifetime.Giving != 0)%>%
    filter(HH.Lifetime.Giving %in% (100:1500000)) %>%
    ggplot() +
    geom_sf(mapping = aes(fill = log(HH.Lifetime.Giving),na.rm=TRUE),
                 color = "#666666", size = 0.025) +
     coord_sf(datum = NA) +
    scale_fill_gradient(low = ("lightblue"),high = ("blue"),labels = scales::dollar) +
    labs(fill = "Household Lifetime Giving") 


spatial_data %>% 
      filter(HH.Lifetime.Giving %in% (100:1500000)) %>% 
      filter(HH.Lifetime.Giving > 0)%>%
  ggplot() +
    geom_sf(mapping = aes(fill = log(HH.Lifetime.Giving),na.rm=TRUE, show.legend = "polygon"),
                 color = "#666666", size = 0.10) +
     coord_sf(datum = NA) +
    scale_fill_gradient(low = ("lightblue"),high = ("blue"),labels = scales::dollar) +
  labs(fill = "Household Lifetime Giving")


#cannot figure out how to exp the legend value after logging HH.Lifetime.Giving 

Part 3 - Modeling

Splitting data and creating a new set for easier analysis


data_split <- initial_split(dataclean, prop = 0.75)

data_train <- training(data_split)
data_test <- testing(data_split)

Linear Models

#These will focus on predicting whether a constituent is a donor or non-donor. 


mod1lm <- lm( Lifetime.Giving ~ Married_simple,
           data = data_train)

mod2lm <- lm( Total.Giving.Years ~ Lifetime.Giving,
           data = data_train)

mod3lm <- lm( Lifetime.Giving ~ region,
           data = data_train)

summary(mod1lm)

Call:
lm(formula = Lifetime.Giving ~ Married_simple, data = data_train)

Residuals:
     Min       1Q   Median       3Q      Max 
   -3245    -3119    -2354    -2354 15826594 

Coefficients:
               Estimate Std. Error t value            Pr(>|t|)    
(Intercept)      2354.1      235.2  10.010 <0.0000000000000002 ***
Married_simple    890.5      438.8   2.029              0.0424 *  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 97730 on 242248 degrees of freedom
Multiple R-squared:  1.7e-05,   Adjusted R-squared:  1.287e-05 
F-statistic: 4.118 on 1 and 242248 DF,  p-value: 0.04244
summary(mod2lm)

Call:
lm(formula = Total.Giving.Years ~ Lifetime.Giving, data = data_train)

Residuals:
    Min      1Q  Median      3Q     Max 
-40.329  -0.552  -0.552  -0.552  39.403 

Coefficients:
                     Estimate    Std. Error t value            Pr(>|t|)    
(Intercept)     0.55182714180 0.00394457013  139.90 <0.0000000000000002 ***
Lifetime.Giving 0.00000363288 0.00000004035   90.04 <0.0000000000000002 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1.941 on 242248 degrees of freedom
Multiple R-squared:  0.03238,   Adjusted R-squared:  0.03238 
F-statistic:  8106 on 1 and 242248 DF,  p-value: < 0.00000000000000022
summary(mod3lm)

Call:
lm(formula = Lifetime.Giving ~ region, data = data_train)

Residuals:
     Min       1Q   Median       3Q      Max 
   -3676    -3676    -3676    -3102 15074639 

Coefficients:
               Estimate Std. Error t value Pr(>|t|)    
(Intercept)      541.85     837.97   0.647 0.517876    
regionDenver    -380.47    2425.77  -0.157 0.875367    
regionNew York  1882.25    1906.28   0.987 0.323450    
regionNor Cal   2560.56    1436.20   1.783 0.074610 .  
regionPortland  -248.66    2366.39  -0.105 0.916311    
regionSeattle     37.53    1843.88   0.020 0.983763    
regionSo Cal    3134.07     895.59   3.499 0.000466 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 104300 on 144506 degrees of freedom
  (97737 observations deleted due to missingness)
Multiple R-squared:  0.0001275, Adjusted R-squared:  8.596e-05 
F-statistic: 3.071 on 6 and 144506 DF,  p-value: 0.005258


ggplot(data = data_train, aes(x = Age, y = log(HH.Lifetime.Giving))) + geom_point(alpha = 1/10) + geom_smooth(method = lm) + facet_wrap(~region) + theme_clean(base_size = 8) + labs(x = "X", y = "Y") +
      ggtitle("Region")
`geom_smooth()` using formula 'y ~ x'

ggplot(data = data_train, aes(x = Age, y = log(HH.Lifetime.Giving))) + geom_point(alpha = 1/10) + geom_smooth(method = lm) + facet_wrap(~nmb_degree) + theme_clean(base_size = 8) + labs(x = "X", y = "Y") +
      ggtitle("Number of Degrees")
`geom_smooth()` using formula 'y ~ x'

ggplot(data = data_train, aes(x = Age, y = log(HH.First.Gift.Amount))) + geom_point(alpha = 1/10) + geom_smooth(method = lm) + facet_wrap(~donorseg_fct) + theme_clean(base_size = 8) + labs(x = "X", y = "Y") +
      ggtitle("Donor Segment")
`geom_smooth()` using formula 'y ~ x'

#This plot actually has some interesting results
ggplot(data = data_train, aes(x = Age, y = log(Lifetime.Giving))) + geom_point(alpha = 1/10) + geom_smooth(method = lm) + facet_wrap(~No_of_Children) + theme_clean(base_size = 8) + labs(x = "X", y = "Y") +
      ggtitle("# Children")
`geom_smooth()` using formula 'y ~ x'

data_train %>% 
  select_if(is.factor) %>% 
  glimpse()
Rows: 242,250
Columns: 57
$ major_gifter           <fct> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0~
$ sex_fct                <fct> F, M, F, F, (Missing), M, F, M, M, F, (Missing), (Missing), (Missing), (Missing), M, (Mi~
$ sex_simple             <fct> F, M, F, F, NA, M, F, M, M, F, NA, NA, NA, NA, M, NA, F, M, F, F, F, F, NA, M, NA, M, M,~
$ married_fct            <fct> N, Y, N, N, N, N, Y, Y, Y, N, N, N, N, N, N, N, N, Y, N, N, Y, N, N, N, N, Y, N, N, Y, Y~
$ donorseg_fct           <fct> Lost Donor, Lapsed Donor, (Missing), (Missing), (Missing), (Missing), Current Donor, (Mi~
$ donorseg_simple        <fct> Lost Donor, Lapsed Donor, NA, NA, NA, NA, Current Donor, NA, Lapsing Donor, Lost Donor, ~
$ contact_fct            <fct> (Missing), (Missing), (Missing), (Missing), (Missing), (Missing), (Missing), (Missing), ~
$ contact_simple         <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, No Phonathon Calls, NA, ~
$ spomail_fct            <fct> (Missing), (Missing), (Missing), (Missing), (Missing), (Missing), (Missing), (Missing), ~
$ spomail_simple         <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, No Phona~
$ jobtitle_fct           <fct> (Missing), (Missing), (Missing), (Missing), (Missing), (Missing), (Missing), President, ~
$ jobtitle_simple        <fct> NA, NA, NA, NA, NA, NA, NA, President, Other, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA~
$ deg1_fct               <fct> (Missing), (Missing), (Missing), Bachelor of Arts, (Missing), (Missing), Bachelor of Art~
$ deg1_simple            <fct> NA, NA, NA, Bachelor of Arts, NA, NA, Bachelor of Arts, Other, NA, Bachelor of Arts, NA,~
$ deg2_fct               <fct> (Missing), (Missing), (Missing), Master of Arts, (Missing), (Missing), (Missing), (Missi~
$ deg2_simple            <fct> NA, NA, NA, Master of Arts, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, Master of Ar~
$ maj1_fct               <fct> (Missing), (Missing), (Missing), Integrated Educ Studies BA, (Missing), (Missing), Socia~
$ maj1_simple            <fct> NA, NA, NA, Other, NA, NA, Other, Other, NA, Other, NA, NA, NA, NA, NA, NA, Other, Other~
$ maj2_fct               <fct> (Missing), (Missing), (Missing), Special Education MA, (Missing), (Missing), (Missing), ~
$ maj2_simple            <fct> NA, NA, NA, Other, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, Other, NA, NA, NA, NA~
$ min1_fct               <fct> (Missing), (Missing), (Missing), Psychology min, (Missing), (Missing), (Missing), (Missi~
$ min1_simple            <fct> NA, NA, NA, Psychology min, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, Other, NA, N~
$ min2_fct               <fct> (Missing), (Missing), (Missing), (Missing), (Missing), (Missing), (Missing), (Missing), ~
$ min2_simple            <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, ~
$ school1_fct            <fct> (Missing), (Missing), (Missing), Donna Ford Attallah College of Educational Studies, (Mi~
$ school1_simple         <fct> NA, NA, NA, Donna Ford Attallah College of Educational Studies, NA, NA, NA, George L. Ar~
$ school2_fct            <fct> (Missing), (Missing), (Missing), Donna Ford Attallah College of Educational Studies, (Mi~
$ school2_simple         <fct> NA, NA, NA, Donna Ford Attallah College of Educational Studies, NA, NA, NA, NA, NA, NA, ~
$ insttype_fct           <fct> (Missing), (Missing), Undergraduate Degree | Undergraduate Degree | Undergraduate Degree~
$ insttype_simple        <fct> NA, NA, Undergraduate Degree | Undergraduate Degree | Undergraduate Degree, Other, NA, U~
$ extra_fct              <fct> (Missing), (Missing), (Missing), Delta Delta Delta|Snow Club|Snow Club|Snow Club|Snow Cl~
$ extra_simple           <fct> NA, NA, NA, Other, NA, NA, Chapman Choir Tour, NA, NA, Other, NA, NA, NA, NA, NA, NA, Ch~
$ hhfirstgift_fct        <fct> (Missing), Chapman Celebrates, (Missing), (Missing), (Missing), (Missing), (Missing), (M~
$ hhfirstgift_simple     <fct> NA, Other, NA, NA, NA, NA, NA, NA, NA, Other, NA, NA, NA, NA, NA, NA, NA, NA, NA, Pre-SR~
$ ch1_enroll_fct         <fct> (Missing), (Missing), (Missing), (Missing), (Missing), (Missing), (Missing), (Missing), ~
$ ch1_enroll_simple      <fct> NA, Program Completed, NA, NA, NA, NA, NA, Program Active, Plan Change, NA, NA, NA, NA, ~
$ ch1_maj_fct            <fct> Business Administration BS, Dance BA|Integrated Educ Studies BA, (Missing), (Missing), (~
$ ch1_maj_simple         <fct> Business Administration BS, Other, NA, NA, NA, NA, NA, Other, Other, NA, NA, NA, NA, NA,~
$ ch1_min_fct            <fct> (Missing), (Missing), (Missing), (Missing), (Missing), (Missing), (Missing), Advertising~
$ ch1_min_simple         <fct> NA, NA, NA, NA, NA, NA, NA, Other, Other, NA, NA, NA, NA, NA, English min, NA, NA, Other~
$ ch1_school_fct         <fct> George L. Argyros School of Business and Economics, Donna Ford Attallah College of Educa~
$ ch1_school_simple      <fct> George L. Argyros School of Business and Economics, Other, NA, NA, NA, NA, NA, Wilkinson~
$ ch1_feeder_fct         <fct> (Missing), Chaparral High School, (Missing), (Missing), (Missing), (Missing), (Missing),~
$ ch1_feeder_simple      <fct> NA, Other, NA, NA, NA, NA, NA, Other, Other, NA, NA, NA, NA, NA, Other, NA, NA, NA, Othe~
$ ch2_enroll_simple      <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, ~
$ ch2_maj_fct            <fct> (Missing), (Missing), (Missing), (Missing), (Missing), (Missing), (Missing), (Missing), ~
$ ch2_maj_simple         <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, ~
$ ch2_min_fct            <fct> (Missing), (Missing), (Missing), (Missing), (Missing), (Missing), (Missing), (Missing), ~
$ ch2_min_simple         <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, ~
$ ch2_school_fct         <fct> (Missing), (Missing), (Missing), (Missing), (Missing), (Missing), (Missing), (Missing), ~
$ ch2_school_simple      <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, ~
$ ch2_feeder_fct         <fct> (Missing), (Missing), (Missing), (Missing), (Missing), (Missing), (Missing), (Missing), ~
$ ch2_feeder_simple      <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, ~
$ region_fct             <fct> (Missing), So Cal, (Missing), So Cal, (Missing), (Missing), Nor Cal, Seattle, (Missing),~
$ region_simple          <fct> NA, So Cal, NA, So Cal, NA, NA, Nor Cal, Seattle, NA, NA, NA, NA, NA, NA, So Cal, NA, NA~
$ age_range_fct          <fct> (Missing), (Missing), 20 < 30 years old, 30 < 40 years old, (Missing), 20 < 30 years old~
$ hh.lifetime.giving_fct <fct> 2125, 1445, 0, 0, 0, 0, 1267, 0, 750, 125, 0, 0, 0, 0, 0, 0, 0, 60, 0, 175, 0, 0, 0, 0, ~

Initial Logistic models

#removing since we didn't use it 12/7
# Set family to binomial to set logistic function
# Run the model on the training set

# donor_logit1 <-
#   glm(hh.lifetime.giving_fct ~ Married_simple,
#       family = "binomial",
#       data = data_train)
# 
# summary(donor_logit1)
# 
# 
# donor_logit2 <-
#   glm(hh.lifetime.giving_fct ~ No_of_Children,
#       family = "binomial",
#       data = data_train)
# 
# summary(donor_logit2)

Large fully processed Logistic model



#summary(data_train$major_gifter)
#Assignment_flag taken out - may add back

donor_logit3 <-
  glm(major_gifter ~ Married + No_of_Children + donorseg_simple +  Total.Giving.Years + nmb_degree,
      family = "binomial",
      data = data_train)

summary(donor_logit3)

Call:
glm(formula = major_gifter ~ Married + No_of_Children + donorseg_simple + 
    Total.Giving.Years + nmb_degree, family = "binomial", data = data_train)

Deviance Residuals: 
    Min       1Q   Median       3Q      Max  
-3.0162  -0.1346  -0.1189  -0.0647   4.2151  

Coefficients:
                              Estimate Std. Error z value             Pr(>|z|)    
(Intercept)                  -3.623014   0.232406 -15.589 < 0.0000000000000002 ***
MarriedY                     -1.196678   0.088444 -13.530 < 0.0000000000000002 ***
No_of_Children                0.610558   0.060093  10.160 < 0.0000000000000002 ***
donorseg_simpleCurrent Donor -0.086079   0.238167  -0.361               0.7178    
donorseg_simpleLapsed Donor  -0.685781   0.244285  -2.807               0.0050 ** 
donorseg_simpleLapsing Donor -0.491440   0.259772  -1.892               0.0585 .  
donorseg_simpleLost Donor    -1.349829   0.232121  -5.815        0.00000000606 ***
Total.Giving.Years            0.206177   0.005601  36.809 < 0.0000000000000002 ***
nmb_degree                   -2.493578   0.146982 -16.965 < 0.0000000000000002 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 9606.7  on 68301  degrees of freedom
Residual deviance: 7052.9  on 68293  degrees of freedom
  (173948 observations deleted due to missingness)
AIC: 7070.9

Number of Fisher Scoring iterations: 8
exp(donor_logit3$coefficients)
                 (Intercept)                     MarriedY               No_of_Children donorseg_simpleCurrent Donor 
                  0.02670207                   0.30219634                   1.84145937                   0.91752216 
 donorseg_simpleLapsed Donor donorseg_simpleLapsing Donor    donorseg_simpleLost Donor           Total.Giving.Years 
                  0.50369656                   0.61174479                   0.25928458                   1.22897028 
                  nmb_degree 
                  0.08261383 
#training predictions for in sample preds 
preds_train <- predict(donor_logit3, newdata = data_train, type = "response") 

#test predicts for OOS (out of sample)
preds_test <- predict(donor_logit3, newdata = data_test, type = "response")

head(preds_train)
     236259      260845      287321      219737       27673      298107 
0.015426706 0.009114444          NA          NA          NA          NA 
head(preds_test)
          4          10          11          14          15          18 
0.132366655 0.002564702 0.888420638 0.136046442 0.742195040 0.002087869 
results_train <- data.frame(
  `truth` = data_train   %>% select(major_gifter) %>% 
    mutate(major_gifter = as.numeric(major_gifter)),
  `Class1` =  preds_train,
  `type` = rep("train",length(preds_train))
)

results_test <- data.frame(
  `truth` = data_test   %>% select(major_gifter) %>% 
    mutate(major_gifter = as.numeric(major_gifter)),
  `Class1` =  preds_test,
  `type` = rep("test",length(preds_test))
)

results <- bind_rows(results_train,results_test)

dim(results_train)
[1] 242250      3
dim(results_test)
[1] 80750     3
dim(results)
[1] 323000      3
p_plot <-
  ggplot(results,
         aes(m = Class1, d = major_gifter, color = type)) +
  geom_roc(labelsize = 2.5,
           #Took the labelsize down to avoid cutoff
           cutoffs.at = c(0.7,0.5,0.3,0.1,0)) +
 #We removed some of the cutoffs to avoid the mashup near the origin.

  #Changed the theme to avoid cutoff plot values.
  theme_classic(base_size = 14) + 
  labs(x = "False Positive Rate", 
       y = "True Positive Rate") +
      ggtitle("ROC Plot: Training and Test")
print(p_plot) 



p_train <-
  ggplot(results_train,
         aes(m = Class1, d = major_gifter, color = type)) +
  geom_roc(labelsize = 3.5,
           cutoffs.at = c(0.7,0.5,0.3,0.1,0)) +
 
  theme_minimal(base_size = 16) + 
  labs(x = "False Positive Rate", 
       y = "True Positive Rate") +
      ggtitle("ROC Plot: Training and Test")

p_test <-
  ggplot(results_test,
         aes(m = Class1, d = major_gifter, color = type)) +
  geom_roc(labelsize = 3.5,
           cutoffs.at = c(0.7,0.5,0.3,0.1,0)) +
 
  theme_minimal(base_size = 16) + 
  labs(x = "False Positive Rate", 
       y = "True Positive Rate") +
      ggtitle("ROC Plot: Training and Test")

Calculating AUC of logistic model 3


#summary(donor_logit3)
#coef(donor_logit3)


#Calculating AUC of both
print(calc_auc(p_train)$AUC)
[1] 0.8918463
print(calc_auc(p_test)$AUC)
[1] 0.8839279

Ridge model with more variables added



data_train %>% map(levels) %>% map(length)
$ID
[1] 0

$Birthdate
[1] 0

$HH.Total.Gifts.FY20.21
[1] 0

$HH.Total.Gifts.FY19.20
[1] 0

$HH.Total.Gifts.FY18.19
[1] 0

$HH.Total.Gifts.FY17.18
[1] 0

$HH.Total.Gifts.FY16.17
[1] 0

$Class.Year
[1] 0

$Category.Codes
[1] 0

$Category.Descriptions
[1] 0

$Spouse.Birthdate
[1] 0

$Spouse.Class.Year
[1] 0

$Sex
[1] 0

$Married
[1] 0

$City
[1] 0

$State
[1] 0

$Zip
[1] 0

$County
[1] 0

$Job.Title
[1] 0

$Degree.Type.1
[1] 0

$Degree.Type.2
[1] 0

$Conferral.Date.1
[1] 0

$Conferral.Date.2
[1] 0

$Major.1
[1] 0

$Major.2
[1] 0

$Minor.1
[1] 0

$Minor.2
[1] 0

$School.1
[1] 0

$School.2
[1] 0

$Institution.Type
[1] 0

$Athletics
[1] 0

$Extracurricular
[1] 0

$Child.1.ID
[1] 0

$Child.1.Class.Year
[1] 0

$Child.1.Enroll.Status
[1] 0

$Child.1.Major
[1] 0

$Child.1.Minor
[1] 0

$Child.1.School
[1] 0

$Child.1.Feeder.School
[1] 0

$Child.2.ID
[1] 0

$Child.2.Class.Year
[1] 0

$Child.2.Enroll.Status
[1] 0

$Child.2.Major
[1] 0

$Child.2.Minor
[1] 0

$Child.2.School
[1] 0

$Child.2.Feeder.School
[1] 0

$Last.Contact.By.Anyone
[1] 0

$Lifetime.Giving
[1] 0

$HH.Lifetime.Giving
[1] 0

$Total.Giving.Years
[1] 0

$Total.Giving.Fiscal.Years
[1] 0

$Max.Consec.Fiscal.Years
[1] 0

$HH.Life.Hard.Credit
[1] 0

$HH.Life.Soft.Credit
[1] 0

$Contact.Rules
[1] 0

$Spouse.Mail.Rules
[1] 0

$HH.First.Gift.Amount
[1] 0

$HH.First.Gift.Date
[1] 0

$HH.First.Gift.Fund
[1] 0

$LegacyLeader..compass.score.
[1] 0

$Months.Since.Last.Gift
[1] 0

$Donor.Segment
[1] 0

$Compass.Score
[1] 0

$Scholarship
[1] 0

$Age
[1] 0

$Spouse.Age
[1] 0

$Assignment_flag
[1] 0

$No_of_Children
[1] 0

$nmb_degree
[1] 0

$Conferral.Date.1.Age
[1] 0

$Conferral.Date.2.Age
[1] 0

$Last.Contact.Age
[1] 0

$HH.First.Gift.Age
[1] 0

$major_gifter
[1] 2

$age_range
[1] 0

$region
[1] 0

$zipcode_slry
[1] 0

$zipslry_range
[1] 0

$sex_fct
[1] 5

$sex_simple
[1] 4

$married_fct
[1] 2

$donorseg_fct
[1] 6

$donorseg_simple
[1] 5

$contact_fct
[1] 166

$contact_simple
[1] 5

$spomail_fct
[1] 111

$spomail_simple
[1] 5

$jobtitle_fct
[1] 12438

$jobtitle_simple
[1] 6

$deg1_fct
[1] 53

$deg1_simple
[1] 6

$deg2_fct
[1] 43

$deg2_simple
[1] 6

$maj1_fct
[1] 1276

$maj1_simple
[1] 6

$maj2_fct
[1] 364

$maj2_simple
[1] 6

$min1_fct
[1] 930

$min1_simple
[1] 6

$min2_fct
[1] 52

$min2_simple
[1] 7

$school1_fct
[1] 17

$school1_simple
[1] 6

$school2_fct
[1] 17

$school2_simple
[1] 6

$insttype_fct
[1] 3293

$insttype_simple
[1] 6

$extra_fct
[1] 8591

$extra_simple
[1] 6

$hhfirstgift_fct
[1] 818

$hhfirstgift_simple
[1] 6

$ch1_enroll_fct
[1] 8

$ch1_enroll_simple
[1] 5

$ch1_maj_fct
[1] 1309

$ch1_maj_simple
[1] 5

$ch1_min_fct
[1] 848

$ch1_min_simple
[1] 5

$ch1_school_fct
[1] 21

$ch1_school_simple
[1] 5

$ch1_feeder_fct
[1] 3013

$ch1_feeder_simple
[1] 5

$ch2_enroll_simple
[1] 5

$ch2_maj_fct
[1] 283

$ch2_maj_simple
[1] 5

$ch2_min_fct
[1] 146

$ch2_min_simple
[1] 5

$ch2_school_fct
[1] 19

$ch2_school_simple
[1] 5

$ch2_feeder_fct
[1] 331

$ch2_feeder_simple
[1] 5

$region_fct
[1] 8

$region_simple
[1] 6

$age_range_fct
[1] 10

$Married_simple
[1] 0

$hh.lifetime.giving_fct
[1] 7067

$HH.Lifetime.Giving.Plus
[1] 0

$Lifetime.Giving.Plus
[1] 0

$average_yearly_donation
[1] 0
ridge_fit2 <- cv.glmnet(HH.Lifetime.Giving.Plus ~ sex_fct + Age + school1_simple + insttype_simple + extra_simple + Married + donorseg_simple + nmb_degree + No_of_Children + jobtitle_simple,
                       data = data_train,
                       alpha = 0)

#Alpha 0 sets the Ridge
print(ridge_fit2)
Call:
cv.glmnet.formula(formula = HH.Lifetime.Giving.Plus ~ sex_fct + 
    Age + school1_simple + insttype_simple + extra_simple + Married + 
    donorseg_simple + nmb_degree + No_of_Children + jobtitle_simple, 
    data = data_train, alpha = 0)

Model fitting options:
    Sparse model matrix: FALSE
    Use model.frame: FALSE
    Number of crossvalidation folds: 10
    Alpha: 0
    Deviance-minimizing lambda: 0.1005957  (+1 SE): 1.240191
print(ridge_fit2$lambda.min)
[1] 0.1005957
print(ridge_fit2$lambda.1se)
[1] 1.240191
plot(ridge_fit2)


ridge_coefs <- data.frame(
'ridge_min' = coef(ridge_fit2, s = ridge_fit2$lambda.min) %>% round(3) %>% as.matrix() %>% as.data.frame(),
'ridge_1se' = coef(ridge_fit2, s = ridge_fit2$lambda.1se) %>% round(3) %>% as.matrix() %>% as.data.frame()
) %>% rename('ridge_min' = 1, 'ridge_1se' = 2)
ridge_coefs
NA

Lasso model 1


#Using cv.glmnet from class
#ls(data_train) 
#is.factor(data_train$major_gifter)
#glimpse(data_train$Lifetime.Giving)

#data_train %>% 
#  select_if(is.factor) %>% 
#  glimpse()



# library(glmnet)
# library(glmnetUtils)
# lasso_fit <- cv.glmnet(HH.Lifetime.Giving.Plus ~ sex_fct + jobtitle_simple + nmb_degree + school1_simple + hhfirstgift_simple + maj1_simple + donorseg_simple + No_of_Children + Married,
#                        data = data_train,
#                        #Alpha 1 for lasso
#                        alpha = 1)


# print(lasso_fit$lambda.min)
# #
# print(lasso_fit$lambda.1se)
# 
# plot(lasso_fit)

Lasso model 2




lasso_fit2 <- cv.glmnet(HH.Lifetime.Giving.Plus ~ sex_fct + Age + school1_simple + insttype_simple + extra_simple + Married + donorseg_simple + nmb_degree + No_of_Children + jobtitle_simple,
                       data = data_train,
                       #Alpha 1 for lasso
                       alpha = 1)


print(lasso_fit2$lambda.min)
[1] 0.02218267
#
print(lasso_fit2$lambda.1se)
[1] 0.1564943
plot(lasso_fit2)

Checking Lasso model 2 for coeff shrink


coef(lasso_fit2)
40 x 1 sparse Matrix of class "dgCMatrix"
                                                                                                        s1
(Intercept)                                                                        2.977390190336220321399
sex_fctF                                                                          -0.063295421071888027797
sex_fctM                                                                           0.000000000000006610965
sex_fctU                                                                           .                      
sex_fctX                                                                           .                      
sex_fct(Missing)                                                                   .                      
Age                                                                                0.047469162883246249218
school1_simpleCollege of Health and Behavioral Sciences                            .                      
school1_simpleDonna Ford Attallah College of Educational Studies                   .                      
school1_simpleGeorge L. Argyros School of Business and Economics                   0.034787105908194705661
school1_simpleLawrence and Kristina Dodge Coll of Film & Media                     .                      
school1_simpleWilkinson Coll of Arts  Humanities  & Soc Sciences                   .                      
school1_simpleOther                                                                .                      
insttype_simpleGraduate Degree                                                     .                      
insttype_simpleLaw JD Full-Time Program                                            .                      
insttype_simpleUndergraduate Degree                                                .                      
insttype_simpleUndergraduate Degree | Undergraduate Degree                         .                      
insttype_simpleUndergraduate Degree | Undergraduate Degree | Undergraduate Degree  .                      
insttype_simpleOther                                                               0.062854709638579198128
extra_simpleChapman Choir Tour                                                     .                      
extra_simpleDisciples on Campus                                                    .                      
extra_simpleFootball                                                               .                      
extra_simpleInternational Student                                                  .                      
extra_simpleWorld Campus Afloat/Sem at Sea                                         .                      
extra_simpleOther                                                                  .                      
MarriedN                                                                          -0.370468673088656275105
MarriedY                                                                           0.000809164203377083099
donorseg_simpleAt-Risk Donor                                                       .                      
donorseg_simpleCurrent Donor                                                       1.775624909368799908549
donorseg_simpleLapsed Donor                                                        .                      
donorseg_simpleLapsing Donor                                                       0.304058775117803548049
donorseg_simpleLost Donor                                                         -0.330156786744252639387
nmb_degree                                                                         .                      
No_of_Children                                                                     .                      
jobtitle_simpleAttorney                                                            .                      
jobtitle_simpleOwner                                                               .                      
jobtitle_simplePresident                                                           .                      
jobtitle_simpleTeacher                                                             .                      
jobtitle_simpleUnknown Position                                                    .                      
jobtitle_simpleOther                                                               .                      
#Default setting is lambda.1se

#From the book - showing convergence with lambda values
plot(lasso_fit2$glmnet.fit, xvar="lambda")

#abline(v=log(c(lasso_fit$lambda.min, lasso_fit$lambda.1se)), lty=2)

Elasticnet model part 1


enet_mod <- cva.glmnet(HH.Lifetime.Giving.Plus ~ sex_fct + Age + school1_simple + insttype_simple + extra_simple + Married + donorseg_simple + nmb_degree + No_of_Children + jobtitle_simple,
                       data = data_train,
                       alpha = seq(0,1, by = 0.1))

print(enet_mod)
Call:
cva.glmnet.formula(formula = HH.Lifetime.Giving.Plus ~ sex_fct + 
    Age + school1_simple + insttype_simple + extra_simple + Married + 
    donorseg_simple + nmb_degree + No_of_Children + jobtitle_simple, 
    data = data_train, alpha = seq(0, 1, by = 0.1))

Model fitting options:
    Sparse model matrix: FALSE
    Use model.frame: FALSE
    Alpha values: 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1
    Number of crossvalidation folds for lambda: 10
plot(enet_mod)

NA
NA

Elasticnet model part 2


minlossplot(enet_mod, 
            cv.type = "min")


get_alpha <- function(fit) {
  alpha <- fit$alpha
  error <- sapply(fit$modlist, 
                  function(mod) {min(mod$cvm)})
  alpha[which.min(error)]
}

get_model_params <- function(fit) {
  alpha <- fit$alpha
  lambdaMin <- sapply(fit$modlist, `[[`, "lambda.min")
  lambdaSE <- sapply(fit$modlist, `[[`, "lambda.1se")
  error <- sapply(fit$modlist, function(mod) {min(mod$cvm)})
  best <- which.min(error)
  data.frame(alpha = alpha[best], lambdaMin = lambdaMin[best],
             lambdaSE = lambdaSE[best], eror = error[best])
}

best_alpha <- get_alpha(enet_mod)
print(best_alpha)
[1] 0.4
get_model_params(enet_mod)

best_mod <- enet_mod$modlist[[which(enet_mod$alpha == best_alpha)]]

print(best_mod)

Call:  glmnet::cv.glmnet(x = x, y = y, weights = ..1, offset = ..2,      nfolds = nfolds, foldid = foldid, alpha = a) 

Measure: Mean-Squared Error 

     Lambda Index Measure      SE Nonzero
min 0.04195    42   2.314 0.07425      25
1se 0.24571    23
minlossplot(enet_mod, cv.type = "min")

Ridges plots - could be useful for plotting donations vs donor segment


library('ggridges')

summary(data_train$variable)
Length  Class   Mode 
     0   NULL   NULL 
ggplot(data_train, aes(x = HH.Lifetime.Giving, y = region)) + geom_density_ridges(rel_min_height = 0.005) + xlim(c(25000, 100000)) + 
      ggtitle("HH Lifetime Giving by Region")
Picking joint bandwidth of 8190


#removing ID zip and nonnumeric 
corrplot_data <- dataclean[-c(1:48,52:56,58:60,63,66:67,70:72,74:81,83:138)]

#Convert from character to numeric data type
convert_fac2num <- function(x){
  as.numeric(as.factor(x))
}

corrplot_data <- mutate_at(corrplot_data,
                     .vars = c(1:12),
                     .funs = convert_fac2num)
#making a matrix

#creating correlation
col <- colorRampPalette(c("#BB4400", "#EE9990", 
  "#FFFFFF", "#77AAEE", "#4477BB"))
corrplot(cd_cor, method="color", col=col(100),
  type="lower", addCoef.col = "black",
  tl.pos="lt", tl.col="black", 
  tl.cex=0.7, tl.srt=45, 
  number.cex=0.7,
  diag=FALSE)


#correlation matrix
# pairs(~Age + Months.Since.Last.Gift + donorseg_fct + 
#     nmb_degree + No_of_Children + HH.First.Gift.Age + HH.First.Gift.Amount + Total.Giving.Years,
#     col = corrplot_data$HH.Lifetime.Giving,
#     data = corrplot_data, 
#     main = "Donor Scatter Plot Matrix")

#worthless.. 

ggplot(data = corrplot_data, aes(x = nmb_degree, y = HH.Lifetime.Giving)) + 
  geom_point(aplha = 1/10)+
  geom_smooth(method = "lm", color ="red") 
`geom_smooth()` using formula 'y ~ x'

Random Forest


training <- subset(dataclean, select= c(major_gifter,Age,sex_fct,Lifetime.Giving.Plus,jobtitle_simple
                                         ,No_of_Children,region_fct,nmb_degree,Assignment_flag
                                         ,donorseg_simple,Months.Since.Last.Gift,Last.Contact.Age
                                         ,age_range_fct,school1_simple,insttype_simple,HH.First.Gift.Amount,Total.Giving.Years
                                         ,average_yearly_donation))



rf_fit_donor <- randomForest(Lifetime.Giving.Plus ~ ., 
                       data = training,
                       type = classification,
                       mtry = 5,
                       na.action = na.roughfix,
                       ntree = 50,
                       importance=TRUE
                       )

print(rf_fit_donor)

Call:
 randomForest(formula = Lifetime.Giving.Plus ~ ., data = training,      type = classification, mtry = 5, ntree = 50, importance = TRUE,      na.action = na.roughfix) 
               Type of random forest: regression
                     Number of trees: 50
No. of variables tried at each split: 5

          Mean of squared residuals: 0.1117669
                    % Var explained: 97.87

plot(rf_fit_donor)


varImpPlot(rf_fit_donor, sort = TRUE, 
           n.var = 5,
           type = 2, class = NULL, scale = TRUE, 
           main = deparse(substitute(rf_fit_donor)))


varImpPlot(rf_fit_donor,type = 1,scale = FALSE,n.var = 5,sort = TRUE)


#Plotting Depth of Node usage

# plot_min_depth_distribution(
#   rf_fit_donor,
#   k = 10,
#   min_no_of_trees = 0,
#   mean_sample = "top_trees",
#   mean_scale = FALSE,
#   mean_round = 2,
#   main = "Distribution of minimal depth and its mean"
# )


plot_min_depth_distribution(rf_fit_donor)

#Splitting Category out to check if the category is useful for analysis
#data_category_split_out <- dataclean %>%
 # mutate(Category.Codes = trim(strsplit(as.character(Category.Codes), "|", fixed = TRUE))) %>%
 # unnest(Category.Codes) %>% pivot_wider(names_from = Category.Codes,values_from =Category.Codes, values_fn = length)

#We ran analysis and did not find the data useful
LS0tDQp0aXRsZTogIkJST0NPREUgU3VtbWFyeSBTdGF0aXN0aWNzIg0KYXV0aG9yOiAiQWFyb24gV2lsbGlzLCBDYW5ub24gQnJvb2tlLCBKb3NodWEgSGVuZGVyc29uLCBSeWFuIFJhZGNsaWZmIg0Kc3VidGl0bGU6ICJCVVM2OTYgRmluYWwgUHJvamVjdCB2MjMiDQpnaXRodWI6IGh0dHBzOi8vZ2l0aHViLmNvbS9jYW5ub25icm9va2UvQlJPQ09ERV9GaW5hbF9Qcm9qZWN0DQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCg0KIyBQbGVhc2UgbGVhdmUgdGhpcyBjb2RlIGNodW5rIGFzIGlzLiBJdCBtYWtlcyBzb21lIHNsaWdodCBmb3JtYXR0aW5nIGNoYW5nZXMgdG8gYWx0ZXIgdGhlIG91dHB1dCB0byBiZSBtb3JlIGFlc3RoZXRpY2FsbHkgcGxlYXNpbmcuIA0KDQpsaWJyYXJ5KCdrbml0cicpDQoNCg0KIyBDaGFuZ2UgdGhlIG51bWJlciBpbiBzZXQgc2VlZCB0byB5b3VyIG93biBmYXZvcml0ZSBudW1iZXINCnNldC5zZWVkKDE4MTgpDQpvcHRpb25zKHdpZHRoPTcwKQ0Kb3B0aW9ucyhzY2lwZW49OTkpDQoNCg0KIyB0aGlzIHNldHMgdGV4dCBvdXRwdXR0ZWQgaW4gY29kZSBjaHVua3MgdG8gc21hbGwNCm9wdHNfY2h1bmskc2V0KHRpZHkub3B0cz1saXN0KHdpZHRoLndyYXA9NTApLHRpZHk9VFJVRSwgc2l6ZSA9ICJ2c21hbGwiKSAgDQpvcHRzX2NodW5rJHNldChtZXNzYWdlID0gRkFMU0UsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICB3YXJuaW5nID0gRkFMU0UsDQogICAgICAgICAgICAgICAjICJjYWNoaW5nIiBzdG9yZXMgb2JqZWN0cyBpbiBjb2RlIGNodW5rcyBhbmQgb25seSByZXdyaXRlcyBpZiB5b3UgY2hhbmdlIHRoaW5ncw0KICAgICAgICAgICAgICAgY2FjaGUgPSBUUlVFLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICMgYXV0b21hdGljYWxseSBkb3dubG9hZHMgZGVwZW5kZW5jeSBmaWxlcw0KICAgICAgICAgICAgICAgYXV0b2RlcCA9IFRSVUUsDQogICAgICAgICAgICAgICAjIA0KICAgICAgICAgICAgICAgY2FjaGUuY29tbWVudHMgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICMgDQogICAgICAgICAgICAgICBjb2xsYXBzZSA9IFRSVUUsDQogICAgICAgICAgICAgICAjIGNoYW5nZSBmaWcud2lkdGggYW5kIGZpZy5oZWlnaHQgdG8gY2hhbmdlIHRoZSBjb2RlIGhlaWdodCBhbmQgd2lkdGggYnkgZGVmYXVsdA0KICAgICAgICAgICAgICAgZmlnLndpZHRoID0gNS41LCAgDQogICAgICAgICAgICAgICBmaWcuaGVpZ2h0ID0gNC41LA0KICAgICAgICAgICAgICAgZmlnLmFsaWduPSdjZW50ZXInKQ0KDQoNCmBgYA0KDQpgYGB7ciBzZXR1cC0yfQ0KDQojIEFsd2F5cyBwcmludCB0aGlzIG91dCBiZWZvcmUgeW91ciBhc3NpZ25tZW50DQpzZXNzaW9uSW5mbygpDQpnZXR3ZCgpDQoNCmBgYA0KDQoNCjwhLS0gIyMjIHN0YXJ0IGFuc3dlcmluZyB5b3VyIHByb2JsZW0gc2V0IGhlcmUgLS0+DQo8IS0tIFlvdSBtYXkgZXhwb3J0IHlvdXIgaG9tZXdvcmsgaW4gZWl0aGVyIGh0bWwgb3IgcGRmLCB3aXRoIHRoZSBmb3JtZXIgdXN1YWxseSBiZWluZyBlYXNpZXIuIA0KICAgICBUbyBleHBvcnQgb3IgY29tcGlsZSB5b3VyIFJtZCBmaWxlOiBjbGljayBhYm92ZSBvbiAnS25pdCcgdGhlbiAnS25pdCB0byBIVE1MJyAtLT4NCjwhLS0gQmUgc3VyZSB0byBzdWJtaXQgYm90aCB5b3VyIC5SbWQgZmlsZSBhbmQgdGhlIGNvbXBpbGVkIC5odG1sIG9yIC5wZGYgZmlsZSBmb3IgZnVsbCBjcmVkaXQgLS0+DQoNCg0KYGBge3Igc2V0dXAtM30NCg0KIyBsb2FkIGFsbCB5b3VyIGxpYnJhcmllcyBpbiB0aGlzIGNodW5rIA0KbGlicmFyeSgndGlkeXZlcnNlJykNCmxpYnJhcnkoImZzIikNCmxpYnJhcnkoJ2hlcmUnKQ0KbGlicmFyeSgnZHBseXInKQ0KbGlicmFyeSgndGlkeXZlcnNlJykNCmxpYnJhcnkoJ2dncGxvdDInKQ0KbGlicmFyeSgnZ2dyZXBlbCcpDQpsaWJyYXJ5KCdnZ3RoZW1lcycpDQpsaWJyYXJ5KCdmb3JjYXRzJykNCmxpYnJhcnkoJ3JzYW1wbGUnKQ0KbGlicmFyeSgnbHVicmlkYXRlJykNCmxpYnJhcnkoJ2dndGhlbWVzJykNCmxpYnJhcnkoJ2thYmxlRXh0cmEnKQ0KbGlicmFyeSgncGFzdGVjcycpDQpsaWJyYXJ5KCd2aXJpZGlzJykNCmxpYnJhcnkoJ3Bsb3RseScpDQpsaWJyYXJ5KCd0aWR5cXVhbnQnKQ0KbGlicmFyeSgnc2NhbGVzJykNCmxpYnJhcnkoImdkYXRhIikNCmxpYnJhcnkoImNvcnJwbG90IikNCmxpYnJhcnkoInVyYm5tYXByIikNCmxpYnJhcnkoInVzbWFwIikNCmxpYnJhcnkoInVzZGF0YSIpDQpsaWJyYXJ5KCJ0aWR5Y2Vuc3VzIikNCmxpYnJhcnkoInVyYm50aGVtZXMiKQ0KbGlicmFyeSgicmFuZG9tRm9yZXN0IikNCmxpYnJhcnkoInJhbmRvbUZvcmVzdEV4cGxhaW5lciIpDQpsaWJyYXJ5KCdnbG1uZXQnKQ0KbGlicmFyeSgnZ2xtbmV0VXRpbHMnKQ0KbGlicmFyeSgncGxvdFJPQycpDQpsaWJyYXJ5KCdnZ3JpZGdlcycpDQoNCg0KDQojaW5zdGFsbC5wYWNrYWdlcygicmVtb3RlcyIpDQojcmVtb3Rlczo6aW5zdGFsbF9naXRodWIoIlVyYmFuSW5zdGl0dXRlL3VyYm50aGVtZXMiLCBidWlsZF92aWduZXR0ZXMgPSBUUlVFKQ0KDQojIG5vdGUsIGRvIG5vdCBydW4gaW5zdGFsbC5wYWNrYWdlcygpIGluc2lkZSBhIGNvZGUgY2h1bmsuIGluc3RhbGwgdGhlbSBpbiB0aGUgY29uc29sZSBvdXRzaWRlIG9mIGEgY29kZSBjaHVuay4gDQoNCmBgYA0KDQoNCg0KIyMgUGFydCAxIC0gRmluYWwgUHJvamVjdCBDbGVhbmluZyBhbmQgU3VtbWFyeSBTdGF0aXN0aWNzIA0KDQoxYSkgTG9hZGluZyBkYXRhDQoNCmBgYHtyfQ0KDQojUmVhZGluZyB0aGUgZGF0YSBpbiBhbmQgZG9pbmcgbWlub3IgaW5pdGlhbCBjbGVhbmluZyBpbiB0aGUgZnVuY3Rpb24gY2FsbA0KI1JlcHJvZHVjaWJsZSBkYXRhIGFuYWx5c2lzIHNob3VsZCBhdm9pZCBhbGwgYXV0b21hdGljIHN0cmluZyB0byBmYWN0b3IgY29udmVyc2lvbnMuDQojc3RyaXAud2hpdGUgcmVtb3ZlcyB3aGl0ZSBzcGFjZSANCiNuYS5zdHJpbmdzIGlzIGEgc3Vic3RpdHV0aW9uIHNvIGFsbCB0aGF0IGhhdmUgIiIgd2lsbCA9IG5hDQpkYXRhIDwtIHJlYWQuY3N2KGhlcmU6OmhlcmUoImZpbmFsX3Byb2plY3QiLCAiZG9ub3JfZGF0YS5jc3YiKSwNCiAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICBzdHJpcC53aGl0ZSA9IFRSVUUsDQogICAgICAgICAgICAgICAgIG5hLnN0cmluZ3MgPSAiIikNCg0KDQoNCmBgYA0KDQoNCjFiKSBGaXhpbmcgdGhlIHdvbmt5IERPQiAmIERhdGEgY2xlYW51cA0KDQpgYGB7cn0NCg0KIyhCaXJ0aGRhdGUgYW5kIEFnZSwgSUQgYXMgYSBudW1iZXIpYWRkaW5nIERPQiAoQWdlL1Nwb3VzZSBBZ2UpIGluIHllYXJzIGNvbHVtbnMgYW5kIGFkZGluZyB0d28gZmllbGRzIGZvciBhc3NpZ25tZW50IGFuZCBudW1iZXIgb2YgY2hpbGRyZW4gYW5kIG51bWJlciBvZiBkZWdyZWVzDQpkYXRhY2xlYW4gPC0gZGF0YSAlPiUNCiAgbXV0YXRlKEJpcnRoZGF0ZSA9IGlmZWxzZShCaXJ0aGRhdGUgPT0gIjAwMDEtMDEtMDEiLCBOQSwgQmlydGhkYXRlKSkgJT4lDQogIG11dGF0ZShCaXJ0aGRhdGUgPSBtZHkoQmlydGhkYXRlKSkgJT4lDQogIG11dGF0ZShBZ2UgPSBhcy5udW1lcmljKGZsb29yKGludGVydmFsKHN0YXJ0PSBCaXJ0aGRhdGUsIGVuZD1TeXMuRGF0ZSgpKS9kdXJhdGlvbihuPTEsIHVuaXQ9InllYXJzIikpKSkgJT4lDQogIG11dGF0ZShTcG91c2UuQmlydGhkYXRlID0gaWZlbHNlKFNwb3VzZS5CaXJ0aGRhdGUgPT0gIjAwMDEtMDEtMDEiLCBOQSwgU3BvdXNlLkJpcnRoZGF0ZSkpICU+JQ0KICBtdXRhdGUoU3BvdXNlLkJpcnRoZGF0ZSA9IG1keShTcG91c2UuQmlydGhkYXRlKSkgJT4lDQogIG11dGF0ZShTcG91c2UuQWdlID0gYXMubnVtZXJpYyhmbG9vcihpbnRlcnZhbChzdGFydD0gU3BvdXNlLkJpcnRoZGF0ZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuZD1TeXMuRGF0ZSgpKS9kdXJhdGlvbihuPTEsIHVuaXQ9InllYXJzIikpKSkgJT4lDQogIG11dGF0ZShJRCA9IGFzLm51bWVyaWMoSUQpKSAlPiUgDQogIG11dGF0ZShBc3NpZ25tZW50X2ZsYWcgPSBpZmVsc2UoaXMubmEoQXNzaWdubWVudC5OdW1iZXIpLCAwLDEpKSAlPiUgDQogIG11dGF0ZSggTm9fb2ZfQ2hpbGRyZW4gPSBpZmVsc2UoaXMubmEoQ2hpbGQuMS5JRCksMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoaXMubmEoQ2hpbGQuMi5JRCksMSwyKSkpJT4lDQogbXV0YXRlKElEID0gYXMubnVtZXJpYyhJRCkpICU+JSANCiAgICBtdXRhdGUoIG5tYl9kZWdyZWUgPSBpZmVsc2UoaXMubmEoRGVncmVlLlR5cGUuMSksMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoaXMubmEoRGVncmVlLlR5cGUuMiksMSwyKSkpICU+JQ0KI2NvbmZlcnJhbCBkYXRlcw0KICBtdXRhdGUoQ29uZmVycmFsLkRhdGUuMSA9IGlmZWxzZShDb25mZXJyYWwuRGF0ZS4xID09ICIwMDAxLTAxLTAxIiwgTkEsIENvbmZlcnJhbC5EYXRlLjEpKSAlPiUNCiAgbXV0YXRlKENvbmZlcnJhbC5EYXRlLjEgPSBtZHkoQ29uZmVycmFsLkRhdGUuMSkpICU+JQ0KICBtdXRhdGUoQ29uZmVycmFsLkRhdGUuMS5BZ2UgPSBhcy5udW1lcmljKGZsb29yKGludGVydmFsKHN0YXJ0PSBDb25mZXJyYWwuRGF0ZS4xLCBlbmQ9U3lzLkRhdGUoKSkvZHVyYXRpb24obj0xLCB1bml0PSJ5ZWFycyIpKSkpICU+JQ0KICANCiAgbXV0YXRlKENvbmZlcnJhbC5EYXRlLjIgPSBpZmVsc2UoQ29uZmVycmFsLkRhdGUuMiA9PSAiMDAwMS0wMS0wMSIsIE5BLCBDb25mZXJyYWwuRGF0ZS4yKSkgJT4lDQogIG11dGF0ZShDb25mZXJyYWwuRGF0ZS4yID0gbWR5KENvbmZlcnJhbC5EYXRlLjIpKSAlPiUNCiAgbXV0YXRlKENvbmZlcnJhbC5EYXRlLjIuQWdlID0gYXMubnVtZXJpYyhmbG9vcihpbnRlcnZhbChzdGFydD0gQ29uZmVycmFsLkRhdGUuMiwgZW5kPVN5cy5EYXRlKCkpL2R1cmF0aW9uKG49MSwgdW5pdD0ieWVhcnMiKSkpKSAlPiUNCiAgDQogIG11dGF0ZShMYXN0LkNvbnRhY3QuQnkuQW55b25lID0gaWZlbHNlKExhc3QuQ29udGFjdC5CeS5BbnlvbmUgPT0gIjAwMDEtMDEtMDEiLCBOQSwgTGFzdC5Db250YWN0LkJ5LkFueW9uZSkpICU+JQ0KICBtdXRhdGUoTGFzdC5Db250YWN0LkJ5LkFueW9uZSA9IG1keShMYXN0LkNvbnRhY3QuQnkuQW55b25lKSkgJT4lDQogIG11dGF0ZShMYXN0LkNvbnRhY3QuQWdlID0gYXMubnVtZXJpYyhmbG9vcihpbnRlcnZhbChzdGFydD0gTGFzdC5Db250YWN0LkJ5LkFueW9uZSwgZW5kPVN5cy5EYXRlKCkpL2R1cmF0aW9uKG49MSwgdW5pdD0ieWVhcnMiKSkpKSAlPiUNCiAgDQogbXV0YXRlKEhILkZpcnN0LkdpZnQuRGF0ZSA9IGlmZWxzZShISC5GaXJzdC5HaWZ0LkRhdGUgPT0gIjAwMDEtMDEtMDEiLCBOQSwgSEguRmlyc3QuR2lmdC5EYXRlKSkgJT4lDQogIG11dGF0ZShISC5GaXJzdC5HaWZ0LkRhdGUgPSBtZHkoSEguRmlyc3QuR2lmdC5EYXRlKSkgJT4lDQptdXRhdGUoSEguRmlyc3QuR2lmdC5BZ2UgPSBhcy5udW1lcmljKGZsb29yKGludGVydmFsKHN0YXJ0PSBISC5GaXJzdC5HaWZ0LkRhdGUsIGVuZD1TeXMuRGF0ZSgpKS9kdXJhdGlvbihuPTEsIHVuaXQ9InllYXJzIikpKSkgJT4lIA0KI21ham9yIGdpZnQgDQogIG11dGF0ZShtYWpvcl9naWZ0ZXIgPSBpZmVsc2UoTGlmZXRpbWUuR2l2aW5nID4gNTAwMDAsIDEsMCkgJT4lIGZhY3RvciguLCBsZXZlbHMgPSBjKCIwIiwiMSIpKSkgJT4lDQojc3BsaXR0aW5nIHVwIHRoZSBhZ2UgaW50byByYW5nZXMgYW5kIGNyZWF0aW5nIGNhdGVnb3J5IGZvciBlYXN5IHZpc3VhbGl6YXRpb24gDQogIG11dGF0ZShhZ2VfcmFuZ2UgPSANCiAgICBpZmVsc2UoQWdlICVpbiUgMTA6MTksICIxMCA8IDIwIHllYXJzIG9sZCIsDQogICAgaWZlbHNlKEFnZSAlaW4lIDIwOjI5LCAiMjAgPCAzMCB5ZWFycyBvbGQiLCANCiAgICBpZmVsc2UoQWdlICVpbiUgMzA6MzksICIzMCA8IDQwIHllYXJzIG9sZCIsDQogICAgaWZlbHNlKEFnZSAlaW4lIDQwOjQ5LCAiNDAgPCA1MCB5ZWFycyBvbGQiLA0KICAgIGlmZWxzZShBZ2UgJWluJSA1MDo1OSwgIjUwIDwgNjAgeWVhcnMgb2xkIiwNCiAgICBpZmVsc2UoQWdlICVpbiUgNjA6NjksICI2MCA8IDcwIHllYXJzIG9sZCIsDQogICAgaWZlbHNlKEFnZSAlaW4lIDcwOjc5LCAiNzAgPCA4MCB5ZWFycyBvbGQiLA0KICAgIGlmZWxzZShBZ2UgJWluJSA4MDo4OSwgIjgwIDwgOTAgeWVhcnMgb2xkIiwNCiAgICBpZmVsc2UoQWdlICVpbiUgOTA6MTIwLCAiOTArIHllYXJzIG9sZCIsDQogICAgTkEpKSkpKSkpKSkpICU+JQ0KI2NyZWF0aW5nIGEgcmVnaW9uIGNvbHVtbiB1c2luZyB0aGUgY291bnR5IGRhdGEgYW5kIHRoZSBPTUIgTVNBIChNZXRyb3BvbGl0YW4gU3RhdGlzdGljYWwgQXJlYSkgZGVmaW5pdGlvbnMNCiAgbXV0YXRlKHJlZ2lvbiA9IA0KICAgIGlmZWxzZShDb3VudHkgPT0gIlNhbiBMdWlzIE9iaXNwbyIgJiBTdGF0ZSA9PSAiQ0EiLCAiU28gQ2FsIiwNCiAgICBpZmVsc2UoQ291bnR5ID09ICJLZXJuIiAmIFN0YXRlID09ICJDQSIsICJTbyBDYWwiLA0KICAgIGlmZWxzZShDb3VudHkgPT0gIlNhbiBCZXJuYXJkaW5vIiAmIFN0YXRlID09ICJDQSIsICJTbyBDYWwiLA0KICAgIGlmZWxzZShDb3VudHkgPT0gIlNhbnRhIEJhcmJhcmEiICYgU3RhdGUgPT0gIkNBIiwgIlNvIENhbCIsDQogICAgaWZlbHNlKENvdW50eSA9PSAiVmVudHVyYSIgJiBTdGF0ZSA9PSAiQ0EiLCAiU28gQ2FsIiwNCiAgICBpZmVsc2UoQ291bnR5ID09ICJMb3MgQW5nZWxlcyIgJiBTdGF0ZSA9PSAiQ0EiLCAiU28gQ2FsIiwNCiAgICBpZmVsc2UoQ291bnR5ID09ICJPcmFuZ2UiICYgU3RhdGUgPT0gIkNBIiwgIlNvIENhbCIsDQogICAgaWZlbHNlKENvdW50eSA9PSAiUml2ZXJzaWRlIiAmIFN0YXRlID09ICJDQSIsICJTbyBDYWwiLA0KICAgIGlmZWxzZShDb3VudHkgPT0gIlNhbiBEaWVnbyIgJiBTdGF0ZSA9PSAiQ0EiLCAiU28gQ2FsIiwNCiAgICBpZmVsc2UoQ291bnR5ID09ICJJbXBlcmlhbCIgJiBTdGF0ZSA9PSAiQ0EiLCAiU28gQ2FsIiwNCiAgICBpZmVsc2UoQ291bnR5ID09ICJLaW5nIiAmIFN0YXRlID09ICJXQSIsICJTZWF0dGxlIiwNCiAgICBpZmVsc2UoQ291bnR5ID09ICJTbm9ob21pc2giICYgU3RhdGUgPT0gIldBIiwgIlNlYXR0bGUiLA0KICAgIGlmZWxzZShDb3VudHkgPT0gIlBpZXJjZSIgJiBTdGF0ZSA9PSAiV0EiLCAiU2VhdHRsZSIsDQogICAgaWZlbHNlKENvdW50eSA9PSAiQ2xhY2thbWFzIiAmIFN0YXRlID09ICJPUiIsICJQb3J0bGFuZCIsDQogICAgaWZlbHNlKENvdW50eSA9PSAiQ29sdW1iaWEiICYgU3RhdGUgPT0gIk9SIiwgIlBvcnRsYW5kIiwNCiAgICBpZmVsc2UoQ291bnR5ID09ICJNdWx0bm9tYWgiICYgU3RhdGUgPT0gIk9SIiwgIlBvcnRsYW5kIiwNCiAgICBpZmVsc2UoQ291bnR5ID09ICJXYXNoaW5ndG9uIiAmIFN0YXRlID09ICJPUiIsICJQb3J0bGFuZCIsDQogICAgaWZlbHNlKENvdW50eSA9PSAiWWFtaGlsbCIgJiBTdGF0ZSA9PSAiT1IiLCAiUG9ydGxhbmQiLA0KICAgIGlmZWxzZShDb3VudHkgPT0gIkNsYXJrIiAmIFN0YXRlID09ICJXQSIsICJQb3J0bGFuZCIsDQogICAgaWZlbHNlKENvdW50eSA9PSAiU2thbWFuaWEiICYgU3RhdGUgPT0gIldBIiwgIlBvcnRsYW5kIiwNCiAgICBpZmVsc2UoQ291bnR5ID09ICJEZW52ZXIiICYgU3RhdGUgPT0gIkNPIiwgIkRlbnZlciIsDQogICAgaWZlbHNlKENvdW50eSA9PSAiQXJhcGFob2UiICYgU3RhdGUgPT0gIkNPIiwgIkRlbnZlciIsDQogICAgaWZlbHNlKENvdW50eSA9PSAiSmVmZmVyc29uIiAmIFN0YXRlID09ICJDTyIsICJEZW52ZXIiLA0KICAgIGlmZWxzZShDb3VudHkgPT0gIkFkYW1zIiAmIFN0YXRlID09ICJDTyIsICJEZW52ZXIiLA0KICAgIGlmZWxzZShDb3VudHkgPT0gIkRvdWdsYXMiICYgU3RhdGUgPT0gIkNPIiwgIkRlbnZlciIsDQogICAgaWZlbHNlKENvdW50eSA9PSAiQnJvb21maWVsZCIgJiBTdGF0ZSA9PSAiQ08iLCAiRGVudmVyIiwgICAgDQogICAgaWZlbHNlKENvdW50eSA9PSAiRWxiZXJ0IiAmIFN0YXRlID09ICJDTyIsICJEZW52ZXIiLA0KICAgIGlmZWxzZShDb3VudHkgPT0gIlBhcmsiICYgU3RhdGUgPT0gIkNPIiwgIkRlbnZlciIsDQogICAgaWZlbHNlKENvdW50eSA9PSAiQ2xlYXIgQ3JlZWsiICYgU3RhdGUgPT0gIkNPIiwgIkRlbnZlciIsDQogICAgaWZlbHNlKENvdW50eSA9PSAiQWxhbWVkYSIgJiBTdGF0ZSA9PSAiQ0EiLCAiQmF5IEFyZWEiLA0KICAgIGlmZWxzZShDb3VudHkgPT0gIkNvbnRyYSBDb3N0YSIgJiBTdGF0ZSA9PSAiQ0EiLCAiQmF5IEFyZWEiLA0KICAgIGlmZWxzZShDb3VudHkgPT0gIk1hcmluIiAmIFN0YXRlID09ICJDQSIsICJCYXkgQXJlYSIsDQogICAgaWZlbHNlKENvdW50eSA9PSAiTW9udGVyZXkiICYgU3RhdGUgPT0gIkNBIiwgIkJheSBBcmVhIiwNCiAgICBpZmVsc2UoQ291bnR5ID09ICJOYXBhIiAmIFN0YXRlID09ICJDQSIsICJCYXkgQXJlYSIsDQogICAgaWZlbHNlKENvdW50eSA9PSAiU2FuIEJlbml0byIgJiBTdGF0ZSA9PSAiQ0EiLCAiQmF5IEFyZWEiLA0KICAgIGlmZWxzZShDb3VudHkgPT0gIlNhbiBGcmFuY2lzY28iICYgU3RhdGUgPT0gIkNBIiwgIkJheSBBcmVhIiwNCiAgICBpZmVsc2UoQ291bnR5ID09ICJTYW4gTWF0ZW8iICYgU3RhdGUgPT0gIkNBIiwgIkJheSBBcmVhIiwNCiAgICBpZmVsc2UoQ291bnR5ID09ICJTYW50YSBDbGFyYSIgJiBTdGF0ZSA9PSAiQ0EiLCAiQmF5IEFyZWEiLA0KICAgIGlmZWxzZShDb3VudHkgPT0gIlNhbnRhIENydXoiICYgU3RhdGUgPT0gIkNBIiwgIkJheSBBcmVhIiwNCiAgICBpZmVsc2UoQ291bnR5ID09ICJTb2xhbm8iICYgU3RhdGUgPT0gIkNBIiwgIkJheSBBcmVhIiwNCiAgICBpZmVsc2UoQ291bnR5ID09ICJTb25vbWEiICYgU3RhdGUgPT0gIkNBIiwgIkJheSBBcmVhIiwNCiAgICAgICAgICAgTkEpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkgJT4lDQogIG11dGF0ZShyZWdpb24gPSANCiAgICBpZmVsc2UoQ291bnR5ID09ICJLaW5ncyIgJiBTdGF0ZSA9PSAiTlkiLCAiTmV3IFlvcmsiLA0KICAgIGlmZWxzZShDb3VudHkgPT0gIlF1ZWVucyIgJiBTdGF0ZSA9PSAiTlkiLCAiTmV3IFlvcmsiLA0KICAgIGlmZWxzZShDb3VudHkgPT0gIk5ldyBZb3JrIiAmIFN0YXRlID09ICJOWSIsICJOZXcgWW9yayIsDQogICAgaWZlbHNlKENvdW50eSA9PSAiQnJvbngiICYgU3RhdGUgPT0gIk5ZIiwgIk5ldyBZb3JrIiwNCiAgICBpZmVsc2UoQ291bnR5ID09ICJSaWNobW9uZCIgJiBTdGF0ZSA9PSAiTlkiLCAiTmV3IFlvcmsiLA0KICAgIGlmZWxzZShDb3VudHkgPT0gIldlc3RjaGVzdGVyIiAmIFN0YXRlID09ICJOWSIsICJOZXcgWW9yayIsDQogICAgaWZlbHNlKENvdW50eSA9PSAiQmVyZ2VuIiAmIFN0YXRlID09ICJOWSIsICJOZXcgWW9yayIsDQogICAgaWZlbHNlKENvdW50eSA9PSAiSHVkc29uIiAmIFN0YXRlID09ICJOWSIsICJOZXcgWW9yayIsDQogICAgaWZlbHNlKENvdW50eSA9PSAiUGFzc2FpYyIgJiBTdGF0ZSA9PSAiTlkiLCAiTmV3IFlvcmsiLA0KICAgIGlmZWxzZShDb3VudHkgPT0gIlB1dG5hbSIgJiBTdGF0ZSA9PSAiTlkiLCAiTmV3IFlvcmsiLA0KICAgIGlmZWxzZShDb3VudHkgPT0gIlJvY2tsYW5kIiAmIFN0YXRlID09ICJOWSIsICJOZXcgWW9yayIsDQogICAgaWZlbHNlKENvdW50eSA9PSAiU3VmZm9sayIgJiBTdGF0ZSA9PSAiTlkiLCAiTmV3IFlvcmsiLA0KICAgIGlmZWxzZShDb3VudHkgPT0gIk5hc3NhdSIgJiBTdGF0ZSA9PSAiTlkiLCAiTmV3IFlvcmsiLA0KICAgIGlmZWxzZShDb3VudHkgPT0gIk1pZGRsZXNleCIgJiBTdGF0ZSA9PSAiTkoiLCAiTmV3IFlvcmsiLA0KICAgIGlmZWxzZShDb3VudHkgPT0gIk1vbm1vdXRoIiAmIFN0YXRlID09ICJOSiIsICJOZXcgWW9yayIsDQogICAgaWZlbHNlKENvdW50eSA9PSAiT2NlYW4iICYgU3RhdGUgPT0gIk5KIiwgIk5ldyBZb3JrIiwNCiAgICBpZmVsc2UoQ291bnR5ID09ICJTb21lcnNldCIgJiBTdGF0ZSA9PSAiTkoiLCAiTmV3IFlvcmsiLA0KICAgIGlmZWxzZShDb3VudHkgPT0gIkVzc2V4IiAmIFN0YXRlID09ICJOSiIsICJOZXcgWW9yayIsDQogICAgaWZlbHNlKENvdW50eSA9PSAiVW5pb24iICYgU3RhdGUgPT0gIk5KIiwgIk5ldyBZb3JrIiwNCiAgICBpZmVsc2UoQ291bnR5ID09ICJNb3JyaXMiICYgU3RhdGUgPT0gIk5KIiwgIk5ldyBZb3JrIiwNCiAgICBpZmVsc2UoQ291bnR5ID09ICJTdXNzZXgiICYgU3RhdGUgPT0gIk5KIiwgIk5ldyBZb3JrIiwNCiAgICBpZmVsc2UoQ291bnR5ID09ICJIdW50ZXJkb24iICYgU3RhdGUgPT0gIk5KIiwgIk5ldyBZb3JrIiwNCiAgICBpZmVsc2UoQ291bnR5ID09ICJQaWtlIiAmIFN0YXRlID09ICJOSiIsICJOZXcgWW9yayIsDQogICAgcmVnaW9uKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpICU+JQ0KDQojIGNvZGUgbm9yIGNhbCByZWdpb24gYXMgYWxsIG90aGVycyBpbiBDQSBub3QgYWxyZWFkeSBkZWZpbmVkDQogIG11dGF0ZShyZWdpb24gPSANCiAgICBpZmVsc2UoU3RhdGUgPT0gIkNBIiAmIGlzLm5hKHJlZ2lvbikgPT0gVFJVRSwgIk5vciBDYWwiLCByZWdpb24pKQ0KDQoNCg0KDQoNCiNJbml0aWFsIFJlbW92YWwgb2YgQ29sdW1ucyB0aGF0IHByb3ZpZGUgbm8gYmVuZWZpdCANCg0KZGF0YWNsZWFuIDwtIHN1YnNldChkYXRhY2xlYW4sc2VsZWN0ID0gLWMoQXNzaWdubWVudC5OdW1iZXINCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsQXNzaWdubWVudC5oYXMuSGlzdG9yaWNhbC5NbmdyDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLFN1ZmZpeA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICxBc3NpZ25tZW50LkRhdGUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsQXNzaWdubWVudC5NYW5hZ2VyDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLEFzc2lnbm1lbnQuUm9sZQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICxBc3NpZ25tZW50LlRpdGxlDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLEFzc2lnbm1lbnQuU3RhdHVzDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLFN0cmF0ZWd5DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLFByb2dyZXNzLkxldmVsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLEFzc2lnbm1lbnQuR3JvdXANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsQXNzaWdubWVudC5DYXRlZ29yeQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICxGdW5kaW5nLk1ldGhvZA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsRXhwZWN0ZWQuQm9vay5EYXRlDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICxRdWFsaWZpY2F0aW9uLkFtb3VudA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsRXhwZWN0ZWQuQm9vay5BbW91bnQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLEV4cGVjdGVkLkJvb2suRGF0ZQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsSGFyZC5HaWZ0LlRvdGFsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICxTb2Z0LkNyZWRpdC5Ub3RhbA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsVG90YWwuQXNzaWdubWVudC5HaWZ0cw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsTm8ub2YuUGxlZGdlcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsUHJvcG9zYWwuLg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsUHJvcG9zYWwuTm90ZXMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLEhILkxpZmUuU3BvdXNlLkNyZWRpdA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsTGFzdC5Db250YWN0LkJ5Lk1hbmFnZXINCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLFguLm9mLkNvbnRhY3RzLkJ5Lk1hbmFnZXINCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLERvbm9yU2VhcmNoLlJhbmdlDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICxpV2F2ZS5SYW5nZQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsV2VhbHRoRW5naW5lLlJhbmdlDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICxQaGlsYW50aHJvcGljLkNvbW1pdG1lbnRzDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkpDQojY2xlYW5pbmcgdXAgemlwIGNvZGVzIHJlbW92aW5nIC00IGFmdGVyIA0KZGF0YWNsZWFuJFppcCA8LSBnc3ViKGRhdGFjbGVhbiRaaXAsIHBhdHRlcm49Ii0uKiIsIHJlcGxhY2VtZW50ID0gIiIpDQoNCiNhZGRpbmcgemlwIGNvZGUgZGF0YSBhbmQgY29sdW1uIA0KemlwIDwtIHJlYWQuY3N2KGhlcmU6OmhlcmUoImZpbmFsX3Byb2plY3QiLCAiU2FsYXJ5X1ppcGNvZGUuY3N2IiksDQogICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgc3RyaXAud2hpdGUgPSBUUlVFLA0KICAgICAgICAgICAgICAgICBuYS5zdHJpbmdzID0gIiIpDQoNCg0KI2FkZGluZyB6aXAgc2FsYXJ5IGNvbHVtbg0KZGF0YWNsZWFuIDwtZGF0YWNsZWFuICU+JQ0KICAgIG11dGF0ZSh6aXBjb2RlX3NscnkgPSBWTE9PS1VQKFppcCwgemlwLCBOQU1FLCBTMTkwMl9DMDNfMDAyRSkpICU+JQ0KI3NscnkgcmFuZ2UgDQogIG11dGF0ZSh6aXBzbHJ5X3JhbmdlID0gDQogICAgaWZlbHNlKHppcGNvZGVfc2xyeSAlaW4lIDEwMDAwOjg5OTk5LCAiOTBLLTk5SyIsDQogICAgaWZlbHNlKHppcGNvZGVfc2xyeSAlaW4lIDkwMDAwOjk5OTk5LCAiOTBLLTk5SyIsDQogICAgaWZlbHNlKHppcGNvZGVfc2xyeSAlaW4lIDEwMDAwMDoxNDk5OTksICIxMDBLLTE0OUsiLCANCiAgICBpZmVsc2UoemlwY29kZV9zbHJ5ICVpbiUgMTUwMDAwOjE5OTk5OSwgIjE1MEstMTk5SyIsDQogICAgaWZlbHNlKHppcGNvZGVfc2xyeSAlaW4lIDIwMDAwMDoyNDk5OTksICIyMDBLLTI0OUsiLA0KICAgIGlmZWxzZSh6aXBjb2RlX3NscnkgJWluJSAyNTAwMDA6Mjk5OTk5LCAiMjUwSy0yOTlLIiwNCiAgICBpZmVsc2UoemlwY29kZV9zbHJ5ICVpbiUgMzAwMDAwOjM0OTk5OSwgIjMwMEstMzQ5SyIsDQogICAgaWZlbHNlKHppcGNvZGVfc2xyeSAlaW4lIDM1MDAwMDozOTk5OTksICIzNTBLLTM5OUsiLA0KICAgIGlmZWxzZSh6aXBjb2RlX3NscnkgJWluJSA0MDAwMDA6NDk5OTk5LCAiNDAwSy00OTlLIiwNCiAgICBpZmVsc2UoemlwY29kZV9zbHJ5ICVpbiUgNTAwMDAwOjk5OTk5OSwgIjUwMEstOTk5SyIsDQogICAgTkEpKSkpKSkpKSkpKQ0KDQpzdW0oaXMubmEoZGF0YWNsZWFuJHppcGNvZGVfc2xyeSkpDQoNCiNjb252ZXJ0aW5nIG1hcnJpZWQgWSBhbmQgTiB0byAxIGFuZCAwIA0KZGF0YWNsZWFuIDwtIGRhdGFjbGVhbiAlPiUNCiAgICAgIG11dGF0ZShNYXJyaWVkX3NpbXBsZSA9IGlmZWxzZShNYXJyaWVkID09ICJOIiwwLDEpKQ0KDQoNCmRhdGFjbGVhbiA8LSBkYXRhY2xlYW4gJT4lIA0KICBtdXRhdGUoaGgubGlmZXRpbWUuZ2l2aW5nX2ZjdCA9IGFzLmZhY3RvcihISC5MaWZldGltZS5HaXZpbmcpKSAlPiUNCiAgbXV0YXRlKEhILkxpZmV0aW1lLkdpdmluZy5QbHVzID0gbG9nKEhILkxpZmV0aW1lLkdpdmluZyArIDEpKSAlPiUgDQogIG11dGF0ZShMaWZldGltZS5HaXZpbmcuUGx1cyA9IGxvZyhMaWZldGltZS5HaXZpbmcgKyAxKSkgJT4lIA0KICBtdXRhdGUoYXZlcmFnZV95ZWFybHlfZG9uYXRpb24gPSAoSEguVG90YWwuR2lmdHMuRlkyMC4yMStISC5Ub3RhbC5HaWZ0cy5GWTE5LjIwK0hILlRvdGFsLkdpZnRzLkZZMTguMTkrSEguVG90YWwuR2lmdHMuRlkxNy4xOCtISC5Ub3RhbC5HaWZ0cy5GWTE2LjE3KS81KQ0KDQojYWRkaW5nIHNjaG9sYXJzaGlwIGRhdGEgKHkvbikNCnNjaGxyIDwtIHJlYWQuY3N2KGhlcmU6OmhlcmUoImZpbmFsX3Byb2plY3QiLCAic2Nob2xhcnNoaXAuY3N2IiksDQogICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgc3RyaXAud2hpdGUgPSBUUlVFLA0KICAgICAgICAgICAgICAgICBuYS5zdHJpbmdzID0gIiIpDQoNCiNhZGRpbmcgc2Nob2xhcnNoaXAgY29sdW1uDQpkYXRhY2xlYW4gPC1kYXRhY2xlYW4gJT4lDQogICAgbXV0YXRlKHNjaG9sYXJzaGlwID0gVkxPT0tVUChJRCwgc2NobHIsIElELCBTQ0hPTEFSU0hJUCkpIA0KDQojcmVwbGFjaW5nIE5BIHdpdGggMCANCiBkYXRhY2xlYW4kc2Nob2xhcnNoaXAgPC0gcmVwbGFjZV9uYShkYXRhY2xlYW4kc2Nob2xhcnNoaXAsJzAnKQ0KIA0KI3JlcGxhY2luZyBZIHdpdGggMSANCmRhdGFjbGVhbiRzY2hvbGFyc2hpcDwtaWZlbHNlKGRhdGFjbGVhbiRzY2hvbGFyc2hpcD09IlkiLDEsMCkNCg0KI2NoZWNraW5nIGhvdyBtYW55IGFyZSBODQp0YWJsZShkYXRhY2xlYW4kc2Nob2xhcnNoaXApDQoNCg0KI2NoZWNraW5nIGFuZCBkZWxldGluZyBzY2hvbGFyc2hpcCBjb2x1bW4gDQpjbGFzcyhkYXRhY2xlYW4kc2NobHJfZmN0KQ0KZGF0YWNsZWFuID0gc3Vic2V0KGRhdGFjbGVhbiwgc2VsZWN0ID0gLWMoc2Nob2xhcnNoaXApKQ0KICANCiNjaGVja2luZyBmb3IgZHVwbGljYXRlcyBOID4xIGluZGljYXRlcyBhIHJlY29yZHMgdmFsdWVzIGFyZSBpbiB0aGUgZmlsZSB0d2ljZSANCmRhdGFjbGVhbiAlPiUgZ3JvdXBfYnkoSUQpICU+JSBjb3VudCgpICU+JSBhcnJhbmdlKGRlc2MobikpDQoNCiNyZW1vdmluZyBkdXBsaWNhdGVkIHJlY29yZHMNCmRhdGFjbGVhbiA8LSB1bmlxdWUoZGF0YWNsZWFuKQ0KDQojVmVyaWZ5aW5nIG4gPSAxIG5vIElEIHdpdGggbXVsdGlwbGUgcmVjb3JkcyBjbGVhbmVkIG9mIGR1cGVzDQpkYXRhY2xlYW4gJT4lIGdyb3VwX2J5KElEKSAlPiUgY291bnQoKSAlPiUgYXJyYW5nZShkZXNjKG4pKQ0KDQpgYGANCg0KDQoxZCBDcmVhdGluZyBtYW55IG1hbnkgZmFjdG9yIHZhcmlhYmxlcw0KDQpgYGB7cn0NCg0KZGF0YWNsZWFuIDwtIA0KICBkYXRhY2xlYW4gJT4lIA0KICAjU0VYDQogIG11dGF0ZShzZXhfZmN0ID0gDQogICAgICAgICAgIGZjdF9leHBsaWNpdF9uYShTZXgpLA0Kc2V4X3NpbXBsZSA9IA0KICAgIGZjdF9sdW1wX24oU2V4LCBuID0gNCksDQojTUFSUklFRA0KbWFycmllZF9mY3QgPSANCiAgICAgICAgICAgZmN0X2V4cGxpY2l0X25hKE1hcnJpZWQpLA0KICAjRE9OT1IgU0VHTUVOVA0KICBkb25vcnNlZ19mY3QgPSANCiAgICAgICAgICAgZmN0X2V4cGxpY2l0X25hKERvbm9yLlNlZ21lbnQpLA0KICAgICAgICAgZG9ub3JzZWdfc2ltcGxlID0gDQogICAgICAgICAgIGZjdF9sdW1wX24oRG9ub3IuU2VnbWVudCwgbiA9IDQpLA0KICAjQ09OVEFDVCBSVUxFDQogICAgICAgICBjb250YWN0X2ZjdCA9IA0KICAgICAgICAgICBmY3RfZXhwbGljaXRfbmEoQ29udGFjdC5SdWxlcyksDQogICAgICAgICBjb250YWN0X3NpbXBsZSA9IA0KICAgICAgICAgICBmY3RfbHVtcF9uKENvbnRhY3QuUnVsZXMsIG4gPSA0KSwNCiAgI1NQT1VTRSBNQUlMDQogICAgICAgICBzcG9tYWlsX2ZjdCA9IA0KICAgICAgICAgICBmY3RfZXhwbGljaXRfbmEoU3BvdXNlLk1haWwuUnVsZXMpLA0KICAgICAgICAgc3BvbWFpbF9zaW1wbGUgPSANCiAgICAgICAgICAgZmN0X2x1bXBfbihTcG91c2UuTWFpbC5SdWxlcywgbiA9IDQpLA0KICAjSk9CIFRJVExFDQogICAgICAgICBqb2J0aXRsZV9mY3QgPSANCiAgICAgICAgICAgZmN0X2V4cGxpY2l0X25hKEpvYi5UaXRsZSksDQogICAgICAgICBqb2J0aXRsZV9zaW1wbGUgPSANCiAgICAgICAgICAgZmN0X2x1bXBfbihKb2IuVGl0bGUsIG4gPSA1KSwNCiAgI0RFR1JFRSBUWVBFIDENCiAgICAgICAgIGRlZzFfZmN0ID0gDQogICAgICAgICAgIGZjdF9leHBsaWNpdF9uYShEZWdyZWUuVHlwZS4xKSwNCiAgICAgICAgIGRlZzFfc2ltcGxlID0gDQogICAgICAgICAgIGZjdF9sdW1wX24oRGVncmVlLlR5cGUuMSwgbiA9IDUpLA0KICAjREVHUkVFIFRZUEUgMg0KICAgICAgICAgZGVnMl9mY3QgPSANCiAgICAgICAgICAgZmN0X2V4cGxpY2l0X25hKERlZ3JlZS5UeXBlLjIpLA0KICAgICAgICAgZGVnMl9zaW1wbGUgPSANCiAgICAgICAgICAgZmN0X2x1bXBfbihEZWdyZWUuVHlwZS4yLCBuID0gNSksDQogICNNQUpPUiAxDQogICAgICAgICBtYWoxX2ZjdCA9IA0KICAgICAgICAgICBmY3RfZXhwbGljaXRfbmEoTWFqb3IuMSksDQogICAgICAgICBtYWoxX3NpbXBsZSA9IA0KICAgICAgICAgICBmY3RfbHVtcF9uKE1ham9yLjEsIG4gPSA1KSwNCiAgI01BSk9SIDINCiAgICAgICAgIG1hajJfZmN0ID0gDQogICAgICAgICAgIGZjdF9leHBsaWNpdF9uYShNYWpvci4yKSwNCiAgICAgICAgIG1hajJfc2ltcGxlID0gDQogICAgICAgICAgIGZjdF9sdW1wX24oTWFqb3IuMiwgbiA9IDUpLA0KICAjTUlOT1IgMQ0KICAgICAgICAgbWluMV9mY3QgPSANCiAgICAgICAgICAgZmN0X2V4cGxpY2l0X25hKE1pbm9yLjEpLA0KICAgICAgICAgbWluMV9zaW1wbGUgPSANCiAgICAgICAgICAgZmN0X2x1bXBfbihNaW5vci4xLCBuID0gNSksDQogICNNSU5PUiAyDQogICAgICAgICBtaW4yX2ZjdCA9IA0KICAgICAgICAgICBmY3RfZXhwbGljaXRfbmEoTWlub3IuMiksDQogICAgICAgICBtaW4yX3NpbXBsZSA9IA0KICAgICAgICAgICBmY3RfbHVtcF9uKE1pbm9yLjIsIG4gPSA1KSwNCiAgI1NDSE9PTCAxDQogICAgICAgICBzY2hvb2wxX2ZjdCA9IA0KICAgICAgICAgICBmY3RfZXhwbGljaXRfbmEoU2Nob29sLjEpLA0KICAgICAgICAgc2Nob29sMV9zaW1wbGUgPSANCiAgICAgICAgICAgZmN0X2x1bXBfbihTY2hvb2wuMSwgbiA9IDUpLA0KICAjU0NIT09MIDINCiAgICAgICAgIHNjaG9vbDJfZmN0ID0gDQogICAgICAgICAgIGZjdF9leHBsaWNpdF9uYShTY2hvb2wuMiksDQogICAgICAgICBzY2hvb2wyX3NpbXBsZSA9IA0KICAgICAgICAgICBmY3RfbHVtcF9uKFNjaG9vbC4yLCBuID0gNSksDQogICNJTlNUSVRVVElPTiBUWVBFDQogICAgICAgICBpbnN0dHlwZV9mY3QgPSANCiAgICAgICAgICAgZmN0X2V4cGxpY2l0X25hKEluc3RpdHV0aW9uLlR5cGUpLA0KICAgICAgICAgaW5zdHR5cGVfc2ltcGxlID0gDQogICAgICAgICAgIGZjdF9sdW1wX24oSW5zdGl0dXRpb24uVHlwZSwgbiA9IDUpLA0KICAjRVhUUkFDVVJSSUNVTEFSDQogICAgICAgICBleHRyYV9mY3QgPSANCiAgICAgICAgICAgZmN0X2V4cGxpY2l0X25hKEV4dHJhY3VycmljdWxhciksDQogICAgICAgICBleHRyYV9zaW1wbGUgPSANCiAgICAgICAgICAgZmN0X2x1bXBfbihFeHRyYWN1cnJpY3VsYXIsIG4gPSA1KSwNCiAgI0hIIEZJUlNUIEdJRlQgRlVORA0KICAgICAgICAgaGhmaXJzdGdpZnRfZmN0ID0gDQogICAgICAgICAgIGZjdF9leHBsaWNpdF9uYShISC5GaXJzdC5HaWZ0LkZ1bmQpLA0KICAgICAgICAgaGhmaXJzdGdpZnRfc2ltcGxlID0gDQogICAgICAgICAgIGZjdF9sdW1wX24oSEguRmlyc3QuR2lmdC5GdW5kLCBuID0gNSksDQojQ0hJTEQgMSBFTlJPTEwgU1RBVFVTDQogICAgICAgICBjaDFfZW5yb2xsX2ZjdCA9IA0KICAgICAgICAgICBmY3RfZXhwbGljaXRfbmEoQ2hpbGQuMS5FbnJvbGwuU3RhdHVzKSwNCiAgICAgICAgIGNoMV9lbnJvbGxfc2ltcGxlID0gDQogICAgICAgICAgIGZjdF9sdW1wX24oQ2hpbGQuMS5FbnJvbGwuU3RhdHVzLCBuID0gNCksDQojQ0hJTEQgMSBNQUpPUg0KICAgICAgICAgY2gxX21hal9mY3QgPSANCiAgICAgICAgICAgZmN0X2V4cGxpY2l0X25hKENoaWxkLjEuTWFqb3IpLA0KICAgICAgICAgY2gxX21hal9zaW1wbGUgPSANCiAgICAgICAgICAgZmN0X2x1bXBfbihDaGlsZC4xLk1ham9yLCBuID0gNCksDQojQ0hJTEQgMSBNSU5PUg0KICAgICAgICAgY2gxX21pbl9mY3QgPSANCiAgICAgICAgICAgZmN0X2V4cGxpY2l0X25hKENoaWxkLjEuTWlub3IpLA0KICAgICAgICAgY2gxX21pbl9zaW1wbGUgPSANCiAgICAgICAgICAgZmN0X2x1bXBfbihDaGlsZC4xLk1pbm9yLCBuID0gNCksDQojQ0hJTEQgMSBTQ0hPT0wNCiAgICAgICAgIGNoMV9zY2hvb2xfZmN0ID0gDQogICAgICAgICAgIGZjdF9leHBsaWNpdF9uYShDaGlsZC4xLlNjaG9vbCksDQogICAgICAgICBjaDFfc2Nob29sX3NpbXBsZSA9IA0KICAgICAgICAgICBmY3RfbHVtcF9uKENoaWxkLjEuU2Nob29sLCBuID0gNCksDQojQ0hJTEQgMSBGRUVERVINCiAgICAgICAgIGNoMV9mZWVkZXJfZmN0ID0gDQogICAgICAgICAgIGZjdF9leHBsaWNpdF9uYShDaGlsZC4xLkZlZWRlci5TY2hvb2wpLA0KICAgICAgICAgY2gxX2ZlZWRlcl9zaW1wbGUgPSANCiAgICAgICAgICAgZmN0X2x1bXBfbihDaGlsZC4xLkZlZWRlci5TY2hvb2wsIG4gPSA0KSwNCiNDSElMRCAyIEVOUk9MTCBTVEFUVVMNCiAgICAgICAgIGNoMV9lbnJvbGxfZmN0ID0gDQogICAgICAgICAgIGZjdF9leHBsaWNpdF9uYShDaGlsZC4yLkVucm9sbC5TdGF0dXMpLA0KICAgICAgICAgY2gyX2Vucm9sbF9zaW1wbGUgPSANCiAgICAgICAgICAgZmN0X2x1bXBfbihDaGlsZC4yLkVucm9sbC5TdGF0dXMsIG4gPSA0KSwNCiNDSElMRCAyIE1BSk9SDQogICAgICAgICBjaDJfbWFqX2ZjdCA9IA0KICAgICAgICAgICBmY3RfZXhwbGljaXRfbmEoQ2hpbGQuMi5NYWpvciksDQogICAgICAgICBjaDJfbWFqX3NpbXBsZSA9IA0KICAgICAgICAgICBmY3RfbHVtcF9uKENoaWxkLjIuTWFqb3IsIG4gPSA0KSwNCiNDSElMRCAyIE1JTk9SDQogICAgICAgICBjaDJfbWluX2ZjdCA9IA0KICAgICAgICAgICBmY3RfZXhwbGljaXRfbmEoQ2hpbGQuMi5NaW5vciksDQogICAgICAgICBjaDJfbWluX3NpbXBsZSA9IA0KICAgICAgICAgICBmY3RfbHVtcF9uKENoaWxkLjIuTWlub3IsIG4gPSA0KSwNCiNDSElMRCAyIFNDSE9PTA0KICAgICAgICAgY2gyX3NjaG9vbF9mY3QgPSANCiAgICAgICAgICAgZmN0X2V4cGxpY2l0X25hKENoaWxkLjIuU2Nob29sKSwNCiAgICAgICAgIGNoMl9zY2hvb2xfc2ltcGxlID0gDQogICAgICAgICAgIGZjdF9sdW1wX24oQ2hpbGQuMi5TY2hvb2wsIG4gPSA0KSwNCiNDSElMRCAyIEZFRURFUg0KICAgICAgICAgY2gyX2ZlZWRlcl9mY3QgPSANCiAgICAgICAgICAgZmN0X2V4cGxpY2l0X25hKENoaWxkLjIuRmVlZGVyLlNjaG9vbCksDQogICAgICAgICBjaDJfZmVlZGVyX3NpbXBsZSA9IA0KICAgICAgICAgICBmY3RfbHVtcF9uKENoaWxkLjIuRmVlZGVyLlNjaG9vbCwgbiA9IDQpLA0KI1JlZ2lvbiANCiAgICAgICAgIHJlZ2lvbl9mY3QgPSANCiAgICAgICAgICAgZmN0X2V4cGxpY2l0X25hKHJlZ2lvbiksDQogICAgICAgICByZWdpb25fc2ltcGxlID0gDQogICAgICAgICAgIGZjdF9sdW1wX24ocmVnaW9uLCBuID0gNSksDQojQWdlDQogICAgICAgICBhZ2VfcmFuZ2VfZmN0ID0gDQogICAgICAgICAgIGZjdF9leHBsaWNpdF9uYShhZ2VfcmFuZ2UpLA0KICAgICkNCg0KICAgIA0KDQoNCg0KI2NoZWNraW5nIHRvIHNlZSBpZiBpdHMgYSBmYWN0b3INCiNjbGFzcyhkYXRhY2xlYW4kc2V4X2ZjdCkNCiNjbGFzcyhkYXRhY2xlYW4kZG9ub3JzZWdfZmN0KQ0KI2NsYXNzKGRhdGFjbGVhbiRjb250YWN0X2ZjdCkNCiNjbGFzcyhkYXRhY2xlYW4kc3BvbWFpbF9mY3QpDQoNCiNjaGVja2luZyBsZXZlbHMNCiNsZXZlbHMoZGF0YWNsZWFuJHNleF9zaW1wbGUpDQojbGV2ZWxzKGRhdGFjbGVhbiRkb25vcnNlZ19zaW1wbGUpDQojbGV2ZWxzKGRhdGFjbGVhbiRjb250YWN0X3NpbXBsZSkNCiNsZXZlbHMoZGF0YWNsZWFuJHNwb21haWxfc2ltcGxlKQ0KI2xldmVscyhkYXRhY2xlYW4kaGhmaXJzdGdpZnRfc2ltcGxlKQ0KDQojY3JlYXRpbmcgYSB0YWJsZSBhZ2FpbnN0IFNleCBjb2x1bW4gDQojdGFibGUoZGF0YWNsZWFuJHNleF9mY3QsIGRhdGFjbGVhbiRzZXhfc2ltcGxlKQ0KDQoNCg0KDQoNCg0KDQpgYGANCg0KDQojIyBQYXJ0IDIgLSBTdW1tYXJ5IFN0YXRpc3RpY3MNCg0KDQpSZWdpb24gQW5hbHlzaXMNCg0KYGBge3J9DQojZ3JvdXBpbmcgYnkgcmVnaW9uIGFuZCBhbmFseXppbmcgDQoNCmRhdGFjbGVhbiAlPiUNCiAgZmlsdGVyKEhILkxpZmV0aW1lLkdpdmluZyAhPSAwKSU+JSAjZmlsdGVyaW5nIG91dCB0aGUgMHMgcGVyIG91ciBwcmVzZW50YXRpb24gYW5kIHJlY29tbWVuZGF0aW9ucyANCiAgZ3JvdXBfYnkocmVnaW9uKSAlPiUNCiAgc3VtbWFyaXNlKENvdW50ID0gbGVuZ3RoKHJlZ2lvbiksDQogICAgICAgICAgICBtZWRpYW5fdG90YWxfZ2l2ID0gbWVkaWFuKEhILkxpZmV0aW1lLkdpdmluZykpICU+JQ0KICBhcnJhbmdlKC1Db3VudCkgJT4lDQogIGZpbHRlcihDb3VudCA+PSAxMDApICU+JQ0KICBtdXRhdGUobWVkaWFuX3RvdGFsX2dpdiA9IGRvbGxhcihtZWRpYW5fdG90YWxfZ2l2KSkgJT4lDQogIGthYmxlKGNvbC5uYW1lcyA9IGMoIlJlZ2lvbiIsICJDb3VudCIsICJNZWRpYW4gSEggTGlmZXRpbWUgR2l2aW5nIiksIGFsaWduPXJlcCgnYycsIDMpKSAlPiUNCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiKSwNCiAgICAgICAgICAgICAgICBmdWxsX3dpZHRoID0gRikNCiAgDQoNCmBgYA0KDQoNCkRvbm9yU2VnbWVudCBBbmFseXNpcw0KDQpgYGB7cn0NCiNncm91cGluZyBieSBkb25vcnNlZ21lbnQgYW5kIGFuYWx5emluZyANCiAgZGF0YWNsZWFuICU+JQ0KICBmaWx0ZXIoSEguTGlmZXRpbWUuR2l2aW5nICE9IDApJT4lICNmaWx0ZXJpbmcgMHMgYW5kIGFkZGluZyBtZWRpYW4gcGVyDQogIGdyb3VwX2J5KERvbm9yLlNlZ21lbnQpICU+JQ0KICBzdW1tYXJpc2UoQ291bnQgPSBsZW5ndGgoRG9ub3IuU2VnbWVudCksDQogICAgICAgICAgICBtZWRpYW5fdG90YWxfZ2l2ID0gbWVkaWFuKEhILkxpZmV0aW1lLkdpdmluZykpICU+JQ0KICBhcnJhbmdlKC1Db3VudCkgJT4lDQogIGZpbHRlcihDb3VudCA+PSAxMDApICU+JQ0KICAjYWRkZWQgc2NhbGVzIHBhY2thZ2UgdG8gaGF2ZSB0aGUgdmFsdWVzIHNob3cgaW4gZG9sbGFyIA0KICBtdXRhdGUobWVkaWFuX3RvdGFsX2dpdiA9IChkb2xsYXIobWVkaWFuX3RvdGFsX2dpdikpKSAlPiUNCiAga2FibGUoY29sLm5hbWVzID0gYygiRG9ub3IgU2VnbWVudCIsICJDb3VudCIsICJNZWRpYW4gSEggTGlmZXRpbWUgR2l2aW5nIiksIGFsaWduPXJlcCgnYycsIDMpKSAlPiUNCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiKSwNCiAgICAgICAgICAgICAgICBmdWxsX3dpZHRoID0gRikNCiAgDQoNCmBgYA0KDQpGaXJzdCBnaWZ0IHNpemUgYW5hbHlzaXMNCg0KYGBge3J9DQoNCmRhdGFjbGVhbiAlPiUNCiAgZmlsdGVyKEhILkxpZmV0aW1lLkdpdmluZyAhPSAwKQ0KICBhcSA8LSBxdWFudGlsZShkYXRhY2xlYW4kSEguRmlyc3QuR2lmdC5BbW91bnQsIHByb2JzID0gYyguMjUsLjUwLC43NSwuOSwuOTkpLCBuYS5ybSA9IFRSVUUpDQoNCmFxIDwtIGFzLmRhdGEuZnJhbWUoYXEpDQoNCmFxJGFxIDwtIGRvbGxhcihhcSRhcSkNCg0KYXEgJT4lDQogIGthYmxlKGNvbC5uYW1lcyA9ICJRdWFudGlsZSIpICU+JQ0KICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIpLA0KICAgICAgICAgICAgICAgIGZ1bGxfd2lkdGggPSBGKQ0KICANCg0KYGBgDQoNCkNvbnNlY3V0aXZlIGdpdmluZw0KDQpgYGB7cn0NCiNjb25zZWN1dGl2ZSB5ZWFycyBvZiBnaXZpbmcgDQpkYXRhY2xlYW4gJT4lDQogIGZpbHRlcihNYXguQ29uc2VjLkZpc2NhbC5ZZWFycyA+IDApICU+JQ0KICBnZ3Bsb3QoYWVzKE1heC5Db25zZWMuRmlzY2FsLlllYXJzKSkgKyBnZW9tX2hpc3RvZ3JhbShmaWxsID0gIiMwMDI4NDUiLCBiaW5zID0gMjApICsgDQogIHRoZW1lX2Vjb25vbWlzdF93aGl0ZSgpICsNCiAgZ2d0aXRsZSgiQ29uc2VjdXRpdmUgWWVhcnMgb2YgR2l2aW5nIERpc3RyaWJ1dGlvbiIpICsgDQogIHhsYWIoTlVMTCkgKyB5bGFiKE5VTEwpICsgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLDEyMCwyKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsMTAwMDAwMDAsNTAwMCkpIA0KDQoNCg0KYGBgDQoNCkxpZmV0aW1lIGdpdmluZyBiYXNlZCBvbiBudW1iZXIgb2YgY2hpbGRyZW4gDQoNCmBgYHtyfQ0KZGF0YWNsZWFuICU+JQ0KICBmaWx0ZXIoSEguTGlmZXRpbWUuR2l2aW5nIDw9IDEwMDAwKSAlPiUNCiAgZmlsdGVyKEhILkxpZmV0aW1lLkdpdmluZyA+IDApICU+JQ0KICBtdXRhdGUoYE5vX29mX0NoaWxkcmVuYCA9IGFzLmZhY3RvcihgTm9fb2ZfQ2hpbGRyZW5gKSkgJT4lDQogIGdncGxvdChhZXMoSEguTGlmZXRpbWUuR2l2aW5nLCBmaWxsID0gYE5vX29mX0NoaWxkcmVuYCkpICsgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDMwKSArIHRoZW1lX2Vjb25vbWlzdF93aGl0ZSgpICsNCiAgeGxhYihOVUxMKSArIHlsYWIoTlVMTCkgKyBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsMTAwMDAwLDEwMDApKSArDQogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwxMDAwMDAwMDAsNTAwMCkpICsNCiAgZ2d0aXRsZSgiR2l2aW5nIGRpc3RyaWJ1dGlvbiBhbmQgbnVtYmVyIG9mIGNoaWxkcmVuIikrIA0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiIzAwMjg0NSIsICIjMDBjZmNjIiwgIiNmZjk5NzMiKSkNCg0KDQoNCmBgYA0KDQoNCk1lYW4sIE1lZGlhbiwgYW5kIENvdW50IG9mIEdpdmluZyBpbiBBZ2UgUmFuZ2VzIA0KDQpgYGB7cn0NCg0KYWdlX3JhbmdlX2dpdmluZyA8LSBkYXRhY2xlYW4gJT4lDQogIGdyb3VwX2J5KGFnZV9yYW5nZSkgJT4lDQogIHN1bW1hcmlzZShhdmdfZ2l2aW5nID0gbWVhbihISC5MaWZldGltZS5HaXZpbmcsIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICBtZWRfZ2l2aW5nID0gbWVkaWFuKEhILkxpZmV0aW1lLkdpdmluZywgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICAgIGFtb3VudF9vZl9wZW9wbGVfaW5fYWdlX3JhbmdlID0gbigpKQ0KDQoNCmdsaW1wc2UoYWdlX3JhbmdlX2dpdmluZykNCg0KYGBgDQoNClBsb3R0aW5nIGF2ZXJhZ2UgZ2l2aW5nIGJ5IGFnZSByYW5nZSANCg0KYGBge3J9DQoNCmFnZV9yYW5nZV9naXZpbmcgPC0NCiAgYWdlX3JhbmdlX2dpdmluZyAlPiUNCiAgbXV0YXRlKGFnZV9yYW5nZSA9IGZhY3RvcihhZ2VfcmFuZ2UpKQ0KDQpnZ3Bsb3QoYWdlX3JhbmdlX2dpdmluZywgYWVzKGFnZV9yYW5nZSwgYXZnX2dpdmluZykpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT00NSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoanVzdD0xKSkgKyBsYWJzKHggPSAiQWdlIFJhbmdlIiwgeSA9ICJBdmVyYWdlIEdpdmluZyIpICsNCiAgICAgIGdndGl0bGUoIkF2ZXJhZ2UgR2l2aW5nIENvbXBhcmVkIEFjcm9zcyBBZ2UgUmFuZ2VzIikNCg0KDQpgYGANCg0KDQpDb3VudCBvZiBkb25vcnMgYmFzZWQgb24gYWdlIHJhbmdlIChhbm90aGVyIHdheSB0byBsb29rIGF0IGl0KQ0KDQpgYGB7cn0NCg0KZ2dwbG90KGRhdGFjbGVhbiwgDQogICAgICAgYWVzKGFnZV9yYW5nZSkpICsgDQogICAgICAgZ2VvbV9iYXIoKSArIA0KICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhqdXN0PTEpKSArIA0KICBsYWJzKHRpdGxlID0gIkNvdW50IG9mIEFnZSBSYW5nZXMiLCB4ID0gIiIsIHkgPSAiIikNCiAgDQoNCmBgYA0KDQpCb3hwbG90IG9mIHRoZSBBZ2UgUmFuZ2VzIEFnYWluc3QgdGhlIExpZmV0aW1lIEdpdmluZyBBbW91bnRzIHdpdGggYSBsb2cgc2NhbGUgYXBwbGllZCAtIHRoZSByZWFzb24gd2UgYXBwbGllZCBsb2cgc2NhbGUgaXMgdG8gcmVzb2x2ZSBpc3N1ZXMgd2l0aCB2aXN1YWxpemF0aW9ucyB0aGF0IHNrZXcgdG93YXJkcyBsYXJnZSB2YWx1ZXMgaW4gb3VyIGRhdGFzZXQuIA0KDQpUSElTIENIVUNOSyBXT1VMRCBOT1QgUlVOIE9OIEZJTkFMIENPTVBJTEFUSU9OLiBJVCBDTEVBUkxZIFJBTiBEVVJJTkcgVEhFIFBSRVAgT0YgT1VSIFBPV0VSUE9JTlQgUFJFU0VOVEFUSU9ODQoNCmBgYHtyfQ0KDQojZ2dwbG90KGRhdGFjbGVhbiwgYWVzKGFnZV9yYW5nZSxISC5MaWZldGltZS5HaXZpbmcsZmlsbCA9IGFnZV9yYW5nZSkpICsgDQogIyBnZW9tX2JveHBsb3QoDQogIyBvdXRsaWVyLmNvbG91ciA9ICJyZWQiKSArIA0KICMgc2NhbGVfeV9sb2cxMCgpICsNCiAjIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT00NSxoanVzdD0xKSkgICsgbGFicyh4ID0gIkFnZSBSYW5nZSIsIHkgPSAiTGlmZXRpbWUgR2l2aW5nIEFtb3VudCIpICsNCiAgIyAgICBnZ3RpdGxlKCJMaWZldGltZSBHaXZpbmcgQ29tcGFyZWQgQWNyb3NzIEFnZSBSYW5nZXMiKQ0KICANCg0KYGBgDQoNCjJkKSBTcGxpdHRpbmcgYnkgYWdlIGFuZCBnZW5kZXIgDQoNCmBgYHtyfQ0KDQoNCiNjcmVhdGluZyBib3hwbG90cyANCmRhdGFjbGVhbiAlPiUgDQogIGZpbHRlcihBZ2UgPCAxMDApICU+JSAjcmVtb3ZpbmcgdGhlIHdlaXJkIG91dGxpZXJzIHRoYXQgYXJlIG92ZXIgMTAwIA0KICBmaWx0ZXIoU2V4ICVpbiUgYygiTSIsICJGIikpICU+JQ0KICBnZ3Bsb3QoYWVzKFNleCwgQWdlKSkgKyANCiAgZ2VvbV9ib3hwbG90KCkgKyANCiAgdGhlbWVfZWNvbm9taXN0KCkgKyANCiAgZ2d0aXRsZSgiQWdlcyBvZiBEb25vcnMgQmFzZWQgb24gR2VuZGVyIikgKyANCiAgeGxhYihOVUxMKSArIHlsYWIoTlVMTCkNCiAgDQoNCmBgYA0KDQpHaXZpbmcgYnkgZ2VuZGVyDQoNCmBgYHtyfQ0KDQojcmVtb3ZlIE5BcyBVIFgNCg0KZGF0YWNsZWFuMiA8LSBkYXRhY2xlYW4gJT4lDQogIGZpbHRlcihTZXggJWluJSBjKCJNIiwgIkYiKSkgDQoNCnEgPC0gZ2dwbG90KGRhdGFjbGVhbjIpIA0KcSArIHN0YXRfc3VtbWFyeV9iaW4oDQogIGFlcyh5ID0gSEguTGlmZXRpbWUuR2l2aW5nLCB4ID0gU2V4KSwgDQogIGZ1bi55ID0gIm1lYW4iLCBnZW9tID0gImJhciIpIA0KICANCnN1bW1hcnkoZGF0YWNsZWFuJHNleF9zaW1wbGUpDQoNCmBgYA0KDQpNZWFuIGFnZSBieSBnZW5kZXINCg0KYGBge3J9DQojYnJlYWtkb3duIG9mIHNleHMgDQp0YWxseShncm91cF9ieShkYXRhY2xlYW4sIFNleCkpDQoNCnN1bW1hcml6ZShncm91cF9ieShkYXRhY2xlYW4sIFNleCksIA0KICAgICAgICAgIGF2Z19naXZpbmcgPSBtZWFuKEhILkxpZmV0aW1lLkdpdmluZywgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICBhdmdfYWdlID0gbWVhbihBZ2UsIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgbWVkX2FnZSA9IG1lZGlhbihBZ2UsIG5hLnJtID0gVFJVRSkpDQoNCiNncm91cGluZyBieSBzZXggYW5kIGFnZSByYW5nZSBmb3Igc2xpZGVzIA0KdGFsbHkoZ3JvdXBfYnkoZGF0YWNsZWFuLCBTZXgsIGFnZV9yYW5nZSkpDQoNCg0KDQpgYGANCg0KDQoNCjJlKSBEaXN0cmlidXRpb24gb2YgcGVvcGxlIGluIHRoZSBzdGF0ZXMgdGhhdCB0aGV5IGxpdmUuDQoNCmBgYHtyfQ0KDQogIGRhdGFjbGVhbiAlPiUNCiAgbXV0YXRlKFN0YXRlID0gaWZlbHNlKFN0YXRlID09ICIgIiwgIk5BIiwgU3RhdGUpKSAlPiUNCiAgZmlsdGVyKFN0YXRlICE9ICJOQSIpICU+JQ0KICBncm91cF9ieShTdGF0ZSkgJT4lDQogIHN1bW1hcmlzZShDb3VudCA9IGxlbmd0aChTdGF0ZSkpICU+JQ0KICBmaWx0ZXIoQ291bnQgPiA4MDApICU+JQ0KICBhcnJhbmdlKC1Db3VudCkgJT4lDQogIGthYmxlKGNvbC5uYW1lcyA9IGMoIkRvbm9yJ3MgU3RhdGUiLCAiQ291bnQiKSkgJT4lDQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJjb25kZW5zZWQiKSwNCiAgICAgICAgICAgICAgICBmdWxsX3dpZHRoID0gRikNCiAgDQoNCmBgYA0KDQoyZikgTG9va2luZyBhdCBhbGwgZG9ub3JzIGZpcnN0IGdpZnQgYW1vdW50LiA3NSUgbWFkZSBhIGZpcnN0IGdpZnQgb2YgPDEwMC4gDQoNCmBgYHtyfQ0KDQogbm9fbm9uX2Rvbm9ycyA8LSBkYXRhY2xlYW4gJT4lDQogIGZpbHRlcihMaWZldGltZS5HaXZpbmcgIT0gMCkNCiAgDQpuZCA8LSBxdWFudGlsZShub19ub25fZG9ub3JzJEhILkZpcnN0LkdpZnQuQW1vdW50LCBwcm9icyA9IGMoLjI1LC41MCwuNzUsLjksLjk5KSwgbmEucm0gPSBUUlVFKQ0KDQpuZCA8LSBhcy5kYXRhLmZyYW1lKG5kKQ0KDQpuZCAlPiUNCiAga2FibGUoY29sLm5hbWVzID0gIlF1YW50aWxlIikgJT4lDQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiksDQogICAgICAgICAgICAgICAgZnVsbF93aWR0aCA9IEYpDQogIA0KICANCg0KDQpgYGANCg0KYGBge3J9DQpwIDwtIGRhdGFjbGVhbiAlPiUNCiAgZ2dwbG90KGFlcyhBZ2UpKSArIGdlb21faGlzdG9ncmFtKGJpbnM9MzAsIGZpbGwgPSAiYmx1ZSIpICsgdGhlbWVfZWNvbm9taXN0X3doaXRlKCkgKw0KICBnZ3RpdGxlKCJPdmVyYWxsIERvbm9yIEFnZSBEaXN0cmlidXRpb24iKSArIA0KICB4bGFiKE5VTEwpICsgeWxhYihOVUxMKSArIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoNSwxMDAsYnkgPSAyMCkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgyMCwxMDAsYnkgPSAyMCkpICsgeGxpbShjKDIwLDEwMCkpDQoNCmdncGxvdGx5KHApDQogIA0KcA0KDQpnZ3Bsb3QoZGF0YSA9IGRhdGFjbGVhbiwgYWVzKHggPSBBZ2UpKSArIGdlb21faGlzdG9ncmFtKGZpbGwgPSJibHVlIikrIHhsaW0oYygyMCwxMDApKQ0KDQogIA0KDQoNCmBgYA0KDQpBbm90aGVyIEhpc3RvZ3JhbQ0KDQoNCmBgYHtyfQ0KDQpkYXRhY2xlYW4gJT4lDQogIGZpbHRlcihBZ2UgPj0gMTApICU+JQ0KICBmaWx0ZXIoQWdlIDw9IDkwKSAlPiUNCiAgZ2dwbG90KGFlcyhBZ2UpKSArIGdlb21faGlzdG9ncmFtKGZpbGwgPSAiIzAwMjg0NSIsIGJpbnMgPSAyMCkgKyB0aGVtZV9lY29ub21pc3Rfd2hpdGUoKSArDQogIGdndGl0bGUoIk92ZXJhbGwgRG9ub3IgQWdlIERpc3RyaWJ1dGlvbiIpICsgDQogIHhsYWIoTlVMTCkgKyB5bGFiKE5VTEwpICsgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLDEyMCw1KSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsMTAwMDAwMDAsMjAwMCkpIA0KDQpgYGANCg0KQWdlIGRpc3RyaWJ1dGlvbiBieSBnZW5kZXIgDQoNCmBgYHtyfQ0KI0FnZSBHZW5kZXIgZmlsdGVyZWQgb3V0IGJlbG93IDE1IGFuZCBhYm92ZSA5MCAtIGFsc28gcmVtb3ZlZCBVIFggdGhlIHdlaXJkIHZhbHVlcyANCmRhdGFjbGVhbiAlPiUNCiAgZmlsdGVyKEFnZSA+PSAxNSkgJT4lDQogIGZpbHRlcihBZ2UgPD0gOTApICU+JQ0KICBtdXRhdGUoU2V4ID0gYXMuZmFjdG9yKFNleCkpICU+JQ0KICBmaWx0ZXIoU2V4ICE9ICJVIikgJT4lDQogIGZpbHRlcihTZXggIT0gIlgiKSAlPiUNCiAgZ2dwbG90KGFlcyhBZ2UsIGZpbGwgPSBTZXgpKSArIGdlb21faGlzdG9ncmFtKGJpbnMgPSAyNSkgKyB0aGVtZV9lY29ub21pc3Rfd2hpdGUoKSArDQogIGdndGl0bGUoIkFnZSBEaXN0cmlidXRpb24gYnkgR2VuZGVyIikgKyANCiAgeGxhYihOVUxMKSArIHlsYWIoTlVMTCkgKyBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsMTIwLDEwKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsNTAwMDAsMjAwMCkpICsgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoIiNmZjk5NzMiLCAiIzAwY2ZjYyIpKQ0KYGBgDQoNCkRvbm9yIGFnZSBkaXN0cmlidXRpb24gYnkgbWFyaXRhbCBzdGF0dXMgDQoNCmBgYHtyfQ0KI0FnZSBNYXJpdGFsIFN0YXR1cw0KZGF0YWNsZWFuICU+JQ0KICBmaWx0ZXIoQWdlID49IDIwKSAlPiUNCiAgZmlsdGVyKEFnZSA8PSA4NSkgJT4lDQogIGdncGxvdChhZXMoQWdlLCBmaWxsID0gTWFycmllZCkpICsgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDI1KSArIHRoZW1lX2Vjb25vbWlzdF93aGl0ZSgpICsNCiAgZ2d0aXRsZSgiT3ZlcmFsbCBEb25vciBBZ2UgRGlzdHJpYnV0aW9uIGJ5IE1hcml0YWwgU3RhdHVzIikgKyANCiAgeGxhYihOVUxMKSArIHlsYWIoTlVMTCkgKyBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsMTIwLDUpKSArDQogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCw1MDAwMCwyMDAwKSkgKyBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiI2ZmOTk3MyIsICIjMDBjZmNjIikpDQpgYGANCg0KTWFwcGluZyANCg0KYGBge3J9DQojYWRkIGNvdW50eSBhZnRlciBjb3VudHkgbmFtZSBpbiBvcmRlciB0byB1c2UgVXJibm1hcHINCg0KZGF0YWNsZWFuIDwtIGRhdGFjbGVhbiAlPiUNCiAgbXV0YXRlKENvdW50eSA9DQogICAgICBpZmVsc2UoaXMubmEoQ291bnR5KSA9PSBUUlVFLCBDb3VudHksIHBhc3RlMChDb3VudHksICIgQ291bnR5IikpKSANCiAgICANCmRjX3N0YXRlX2NvdW50eSA8LSBkYXRhY2xlYW4gJT4lDQogIG11dGF0ZShwb2x5bmFtZSA9DQogICAgICBpZmVsc2UoaXMubmEoQ291bnR5KSA9PSBUUlVFLCBDb3VudHksIHBhc3RlMChTdGF0ZSwgIiwiLENvdW50eSkpKQ0KDQpkY19zdGF0ZV9jb3VudHkyIDwtIGZpcHNfY29kZXMgJT4lDQogIG11dGF0ZShwb2x5bmFtZSA9IHBhc3RlMChzdGF0ZSwgIiwiLGNvdW50eSkpICU+JSANCiAgbXV0YXRlKGNvdW50eV9maXBzID0gcGFzdGUwKHN0YXRlX2NvZGUsY291bnR5X2NvZGUpKQ0KDQojQnJpbmcgaW4gdGhlIEZJUFMgZGF0YSB0byBvdXIgZGF0YSBzZXQgc2luY2UgVXJibk1hcHIgdXNlcyBGSVBTDQoNCmNvdW50eW1hcF9kYXRhIDwtIGxlZnRfam9pbihkY19zdGF0ZV9jb3VudHksIGRjX3N0YXRlX2NvdW50eTIsIGJ5ID0gInBvbHluYW1lIikNCg0KDQpzcGF0aWFsX2RhdGEgPC0gbGVmdF9qb2luKGdldF91cmJuX21hcChtYXAgPSAiY291bnRpZXMiLCBzZiA9IFRSVUUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBjb3VudHltYXBfZGF0YSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSAiY291bnR5X2ZpcHMiKQ0KIyBwbG90IG1hcHMNCg0KZ2dwbG90KCkgKw0KICBnZW9tX3NmKHNwYXRpYWxfZGF0YSwNCiAgICAgICAgICBtYXBwaW5nID0gYWVzKGZpbGwgPSBISC5MaWZldGltZS5HaXZpbmcpLA0KICAgICAgICAgIGNvbG9yID0gIiNmZmZmZmYiLCBzaXplID0gMC41MCkgKw0KICBsYWJzKGZpbGwgPSAiSG91c2Vob2xkIExpZmV0aW1lIEdpdmluZyIpDQoNCmNvdW50eV9zZiA8LSBnZXRfdXJibl9tYXAobWFwID0gImNvdW50aWVzIiwgc2YgPSBUUlVFKQ0KDQpjb3VudHlfc2YgJT4lIA0KICBsZWZ0X2pvaW4oY291bnR5bWFwX2RhdGEsIGJ5ID0gImNvdW50eV9maXBzIikgJT4lIA0KICBnZ3Bsb3QoKSArDQogIGdlb21fc2YobWFwcGluZyA9IGFlcyhmaWxsID0gSEguTGlmZXRpbWUuR2l2aW5nKSwNCiAgICAgICAgICBjb2xvciA9ICIjZmZmZmZmIiwgc2l6ZSA9IDAuMjUpICsNCiAgdGhlbWVfZWNvbm9taXN0X3doaXRlKCkgKw0KICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdyA9ICgibGlnaHRibHVlIiksaGlnaCA9ICgiYmx1ZSIpLGxhYmVscyA9IHNjYWxlczo6ZG9sbGFyKSArDQogIGxhYnMoZmlsbCA9ICJIb3VzZWhvbGQgTGlmZXRpbWUgR2l2aW5nIikgKw0KICBjb29yZF9zZihkYXR1bSA9IE5BKQ0KDQpzcGF0aWFsX2RhdGEgJT4lIA0KICAgIGZpbHRlcihzdGF0ZV9uYW1lLnggPT0gIkNhbGlmb3JuaWEiKSAlPiUNCiAgICBmaWx0ZXIoSEguTGlmZXRpbWUuR2l2aW5nICE9IDApJT4lDQogICAgZmlsdGVyKEhILkxpZmV0aW1lLkdpdmluZyAlaW4lICgxMDA6MTUwMDAwMCkpICU+JSANCiAgZ2dwbG90KCkgKw0KICAgIGdlb21fc2YobWFwcGluZyA9IGFlcyhmaWxsID0gbG9nKEhILkxpZmV0aW1lLkdpdmluZyksbmEucm09VFJVRSksDQogICAgICAgICAgICAgICAgIGNvbG9yID0gIiM2NjY2NjYiLCBzaXplID0gMC4xMCkgKw0KICAgICBjb29yZF9zZihkYXR1bSA9IE5BKSArDQogICAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAoImxpZ2h0Ymx1ZSIpLGhpZ2ggPSAoImJsdWUiKSxsYWJlbHMgPSBzY2FsZXM6OmRvbGxhcikgKw0KICBsYWJzKGZpbGwgPSAiSG91c2Vob2xkIExpZmV0aW1lIEdpdmluZyIpDQoNCnNwYXRpYWxfZGF0YSAlPiUgDQogICAgZmlsdGVyKHN0YXRlX25hbWUueCA9PSAiRmxvcmlkYSIpICU+JQ0KICAgIGZpbHRlcihISC5MaWZldGltZS5HaXZpbmcgIT0gMCklPiUNCiAgICBmaWx0ZXIoSEguTGlmZXRpbWUuR2l2aW5nICVpbiUgKDEwMDoxNTAwMDAwKSkgJT4lDQogICAgZ2dwbG90KCkgKw0KICAgIGdlb21fc2YobWFwcGluZyA9IGFlcyhmaWxsID0gbG9nKEhILkxpZmV0aW1lLkdpdmluZyksbmEucm09VFJVRSksDQogICAgICAgICAgICAgICAgIGNvbG9yID0gIiM2NjY2NjYiLCBzaXplID0gMC4wMjUpICsNCiAgICAgY29vcmRfc2YoZGF0dW0gPSBOQSkgKw0KICAgIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gKCJsaWdodGJsdWUiKSxoaWdoID0gKCJibHVlIiksbGFiZWxzID0gc2NhbGVzOjpkb2xsYXIpICsNCiAgICBsYWJzKGZpbGwgPSAiSG91c2Vob2xkIExpZmV0aW1lIEdpdmluZyIpIA0KDQpzcGF0aWFsX2RhdGEgJT4lIA0KICAgICAgZmlsdGVyKEhILkxpZmV0aW1lLkdpdmluZyAlaW4lICgxMDA6MTUwMDAwMCkpICU+JSANCiAgICAgIGZpbHRlcihISC5MaWZldGltZS5HaXZpbmcgPiAwKSU+JQ0KICBnZ3Bsb3QoKSArDQogICAgZ2VvbV9zZihtYXBwaW5nID0gYWVzKGZpbGwgPSBsb2coSEguTGlmZXRpbWUuR2l2aW5nKSxuYS5ybT1UUlVFLCBzaG93LmxlZ2VuZCA9ICJwb2x5Z29uIiksDQogICAgICAgICAgICAgICAgIGNvbG9yID0gIiM2NjY2NjYiLCBzaXplID0gMC4xMCkgKw0KICAgICBjb29yZF9zZihkYXR1bSA9IE5BKSArDQogICAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAoImxpZ2h0Ymx1ZSIpLGhpZ2ggPSAoImJsdWUiKSxsYWJlbHMgPSBzY2FsZXM6OmRvbGxhcikgKw0KICBsYWJzKGZpbGwgPSAiSG91c2Vob2xkIExpZmV0aW1lIEdpdmluZyIpDQoNCiNjYW5ub3QgZmlndXJlIG91dCBob3cgdG8gZXhwIHRoZSBsZWdlbmQgdmFsdWUgYWZ0ZXIgbG9nZ2luZyBISC5MaWZldGltZS5HaXZpbmcgDQoNCmBgYA0KDQoNCiMjIFBhcnQgMyAtIE1vZGVsaW5nDQoNClNwbGl0dGluZyBkYXRhIGFuZCBjcmVhdGluZyBhIG5ldyBzZXQgZm9yIGVhc2llciBhbmFseXNpcw0KDQpgYGAge3J9DQoNCmRhdGFfc3BsaXQgPC0gaW5pdGlhbF9zcGxpdChkYXRhY2xlYW4sIHByb3AgPSAwLjc1KQ0KDQpkYXRhX3RyYWluIDwtIHRyYWluaW5nKGRhdGFfc3BsaXQpDQpkYXRhX3Rlc3QgPC0gdGVzdGluZyhkYXRhX3NwbGl0KQ0KDQpgYGANCg0KDQoNCkxpbmVhciBNb2RlbHMNCg0KYGBge3J9DQojVGhlc2Ugd2lsbCBmb2N1cyBvbiBwcmVkaWN0aW5nIHdoZXRoZXIgYSBjb25zdGl0dWVudCBpcyBhIGRvbm9yIG9yIG5vbi1kb25vci4gDQoNCg0KbW9kMWxtIDwtIGxtKCBMaWZldGltZS5HaXZpbmcgfiBNYXJyaWVkX3NpbXBsZSwNCiAgICAgICAgICAgZGF0YSA9IGRhdGFfdHJhaW4pDQoNCm1vZDJsbSA8LSBsbSggVG90YWwuR2l2aW5nLlllYXJzIH4gTGlmZXRpbWUuR2l2aW5nLA0KICAgICAgICAgICBkYXRhID0gZGF0YV90cmFpbikNCg0KbW9kM2xtIDwtIGxtKCBMaWZldGltZS5HaXZpbmcgfiByZWdpb24sDQogICAgICAgICAgIGRhdGEgPSBkYXRhX3RyYWluKQ0KDQpzdW1tYXJ5KG1vZDFsbSkNCnN1bW1hcnkobW9kMmxtKQ0Kc3VtbWFyeShtb2QzbG0pDQojaW5jcmVhc2luZyB0aGUgZ2l2aW5nIHllYXIgb25lIHllYXIgaW5jcmVhc2UgdG90YWwgZ2l2aW5nIGJ5IDAuMDAzNQ0KDQoNCmdncGxvdChkYXRhID0gZGF0YV90cmFpbiwgYWVzKHggPSBBZ2UsIHkgPSBsb2coSEguTGlmZXRpbWUuR2l2aW5nKSkpICsgZ2VvbV9wb2ludChhbHBoYSA9IDEvMTApICsgZ2VvbV9zbW9vdGgobWV0aG9kID0gbG0pICsgZmFjZXRfd3JhcCh+cmVnaW9uKSArIHRoZW1lX2NsZWFuKGJhc2Vfc2l6ZSA9IDgpICsgbGFicyh4ID0gIlgiLCB5ID0gIlkiKSArDQogICAgICBnZ3RpdGxlKCJSZWdpb24iKQ0KDQoNCmdncGxvdChkYXRhID0gZGF0YV90cmFpbiwgYWVzKHggPSBBZ2UsIHkgPSBsb2coSEguTGlmZXRpbWUuR2l2aW5nKSkpICsgZ2VvbV9wb2ludChhbHBoYSA9IDEvMTApICsgZ2VvbV9zbW9vdGgobWV0aG9kID0gbG0pICsgZmFjZXRfd3JhcCh+bm1iX2RlZ3JlZSkgKyB0aGVtZV9jbGVhbihiYXNlX3NpemUgPSA4KSArIGxhYnMoeCA9ICJYIiwgeSA9ICJZIikgKw0KICAgICAgZ2d0aXRsZSgiTnVtYmVyIG9mIERlZ3JlZXMiKQ0KDQoNCmdncGxvdChkYXRhID0gZGF0YV90cmFpbiwgYWVzKHggPSBBZ2UsIHkgPSBsb2coSEguRmlyc3QuR2lmdC5BbW91bnQpKSkgKyBnZW9tX3BvaW50KGFscGhhID0gMS8xMCkgKyBnZW9tX3Ntb290aChtZXRob2QgPSBsbSkgKyBmYWNldF93cmFwKH5kb25vcnNlZ19mY3QpICsgdGhlbWVfY2xlYW4oYmFzZV9zaXplID0gOCkgKyBsYWJzKHggPSAiWCIsIHkgPSAiWSIpICsNCiAgICAgIGdndGl0bGUoIkRvbm9yIFNlZ21lbnQiKQ0KDQojVGhpcyBwbG90IGFjdHVhbGx5IGhhcyBzb21lIGludGVyZXN0aW5nIHJlc3VsdHMNCmdncGxvdChkYXRhID0gZGF0YV90cmFpbiwgYWVzKHggPSBBZ2UsIHkgPSBsb2coTGlmZXRpbWUuR2l2aW5nKSkpICsgZ2VvbV9wb2ludChhbHBoYSA9IDEvMTApICsgZ2VvbV9zbW9vdGgobWV0aG9kID0gbG0pICsgZmFjZXRfd3JhcCh+Tm9fb2ZfQ2hpbGRyZW4pICsgdGhlbWVfY2xlYW4oYmFzZV9zaXplID0gOCkgKyBsYWJzKHggPSAiWCIsIHkgPSAiWSIpICsNCiAgICAgIGdndGl0bGUoIiMgQ2hpbGRyZW4iKQ0KDQoNCmRhdGFfdHJhaW4gJT4lIA0KICBzZWxlY3RfaWYoaXMuZmFjdG9yKSAlPiUgDQogIGdsaW1wc2UoKQ0KDQoNCmBgYA0KDQoNCkluaXRpYWwgTG9naXN0aWMgbW9kZWxzDQoNCmBgYHtyfQ0KI3JlbW92aW5nIHNpbmNlIHdlIGRpZG4ndCB1c2UgaXQgMTIvNw0KIyBTZXQgZmFtaWx5IHRvIGJpbm9taWFsIHRvIHNldCBsb2dpc3RpYyBmdW5jdGlvbg0KIyBSdW4gdGhlIG1vZGVsIG9uIHRoZSB0cmFpbmluZyBzZXQNCg0KIyBkb25vcl9sb2dpdDEgPC0NCiMgICBnbG0oaGgubGlmZXRpbWUuZ2l2aW5nX2ZjdCB+IE1hcnJpZWRfc2ltcGxlLA0KIyAgICAgICBmYW1pbHkgPSAiYmlub21pYWwiLA0KIyAgICAgICBkYXRhID0gZGF0YV90cmFpbikNCiMgDQojIHN1bW1hcnkoZG9ub3JfbG9naXQxKQ0KIyANCiMgDQojIGRvbm9yX2xvZ2l0MiA8LQ0KIyAgIGdsbShoaC5saWZldGltZS5naXZpbmdfZmN0IH4gTm9fb2ZfQ2hpbGRyZW4sDQojICAgICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsDQojICAgICAgIGRhdGEgPSBkYXRhX3RyYWluKQ0KIyANCiMgc3VtbWFyeShkb25vcl9sb2dpdDIpDQoNCg0KYGBgDQoNCkxhcmdlIGZ1bGx5IHByb2Nlc3NlZCBMb2dpc3RpYyBtb2RlbA0KDQpgYGB7ciBsb2d9DQoNCg0KI3N1bW1hcnkoZGF0YV90cmFpbiRtYWpvcl9naWZ0ZXIpDQojQXNzaWdubWVudF9mbGFnIHRha2VuIG91dCAtIG1heSBhZGQgYmFjaw0KDQpkb25vcl9sb2dpdDMgPC0NCiAgZ2xtKG1ham9yX2dpZnRlciB+IE1hcnJpZWQgKyBOb19vZl9DaGlsZHJlbiArIGRvbm9yc2VnX3NpbXBsZSArICBUb3RhbC5HaXZpbmcuWWVhcnMgKyBubWJfZGVncmVlLA0KICAgICAgZmFtaWx5ID0gImJpbm9taWFsIiwNCiAgICAgIGRhdGEgPSBkYXRhX3RyYWluKQ0KDQpzdW1tYXJ5KGRvbm9yX2xvZ2l0MykNCmV4cChkb25vcl9sb2dpdDMkY29lZmZpY2llbnRzKQ0KDQojdHJhaW5pbmcgcHJlZGljdGlvbnMgZm9yIGluIHNhbXBsZSBwcmVkcyANCnByZWRzX3RyYWluIDwtIHByZWRpY3QoZG9ub3JfbG9naXQzLCBuZXdkYXRhID0gZGF0YV90cmFpbiwgdHlwZSA9ICJyZXNwb25zZSIpIA0KDQojdGVzdCBwcmVkaWN0cyBmb3IgT09TIChvdXQgb2Ygc2FtcGxlKQ0KcHJlZHNfdGVzdCA8LSBwcmVkaWN0KGRvbm9yX2xvZ2l0MywgbmV3ZGF0YSA9IGRhdGFfdGVzdCwgdHlwZSA9ICJyZXNwb25zZSIpDQoNCmhlYWQocHJlZHNfdHJhaW4pDQpoZWFkKHByZWRzX3Rlc3QpDQoNCg0KDQpyZXN1bHRzX3RyYWluIDwtIGRhdGEuZnJhbWUoDQogIGB0cnV0aGAgPSBkYXRhX3RyYWluICAgJT4lIHNlbGVjdChtYWpvcl9naWZ0ZXIpICU+JSANCiAgICBtdXRhdGUobWFqb3JfZ2lmdGVyID0gYXMubnVtZXJpYyhtYWpvcl9naWZ0ZXIpKSwNCiAgYENsYXNzMWAgPSAgcHJlZHNfdHJhaW4sDQogIGB0eXBlYCA9IHJlcCgidHJhaW4iLGxlbmd0aChwcmVkc190cmFpbikpDQopDQoNCnJlc3VsdHNfdGVzdCA8LSBkYXRhLmZyYW1lKA0KICBgdHJ1dGhgID0gZGF0YV90ZXN0ICAgJT4lIHNlbGVjdChtYWpvcl9naWZ0ZXIpICU+JSANCiAgICBtdXRhdGUobWFqb3JfZ2lmdGVyID0gYXMubnVtZXJpYyhtYWpvcl9naWZ0ZXIpKSwNCiAgYENsYXNzMWAgPSAgcHJlZHNfdGVzdCwNCiAgYHR5cGVgID0gcmVwKCJ0ZXN0IixsZW5ndGgocHJlZHNfdGVzdCkpDQopDQoNCnJlc3VsdHMgPC0gYmluZF9yb3dzKHJlc3VsdHNfdHJhaW4scmVzdWx0c190ZXN0KQ0KDQpkaW0ocmVzdWx0c190cmFpbikNCmRpbShyZXN1bHRzX3Rlc3QpDQpkaW0ocmVzdWx0cykNCg0KDQpwX3Bsb3QgPC0NCiAgZ2dwbG90KHJlc3VsdHMsDQogICAgICAgICBhZXMobSA9IENsYXNzMSwgZCA9IG1ham9yX2dpZnRlciwgY29sb3IgPSB0eXBlKSkgKw0KICBnZW9tX3JvYyhsYWJlbHNpemUgPSAyLjUsDQogICAgICAgICAgICNUb29rIHRoZSBsYWJlbHNpemUgZG93biB0byBhdm9pZCBjdXRvZmYNCiAgICAgICAgICAgY3V0b2Zmcy5hdCA9IGMoMC43LDAuNSwwLjMsMC4xLDApKSArDQogI1dlIHJlbW92ZWQgc29tZSBvZiB0aGUgY3V0b2ZmcyB0byBhdm9pZCB0aGUgbWFzaHVwIG5lYXIgdGhlIG9yaWdpbi4NCg0KICAjQ2hhbmdlZCB0aGUgdGhlbWUgdG8gYXZvaWQgY3V0b2ZmIHBsb3QgdmFsdWVzLg0KICB0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZSA9IDE0KSArIA0KICBsYWJzKHggPSAiRmFsc2UgUG9zaXRpdmUgUmF0ZSIsIA0KICAgICAgIHkgPSAiVHJ1ZSBQb3NpdGl2ZSBSYXRlIikgKw0KICAgICAgZ2d0aXRsZSgiUk9DIFBsb3Q6IFRyYWluaW5nIGFuZCBUZXN0IikNCnByaW50KHBfcGxvdCkgDQoNCg0KcF90cmFpbiA8LQ0KICBnZ3Bsb3QocmVzdWx0c190cmFpbiwNCiAgICAgICAgIGFlcyhtID0gQ2xhc3MxLCBkID0gbWFqb3JfZ2lmdGVyLCBjb2xvciA9IHR5cGUpKSArDQogIGdlb21fcm9jKGxhYmVsc2l6ZSA9IDMuNSwNCiAgICAgICAgICAgY3V0b2Zmcy5hdCA9IGMoMC43LDAuNSwwLjMsMC4xLDApKSArDQogDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTYpICsgDQogIGxhYnMoeCA9ICJGYWxzZSBQb3NpdGl2ZSBSYXRlIiwgDQogICAgICAgeSA9ICJUcnVlIFBvc2l0aXZlIFJhdGUiKSArDQogICAgICBnZ3RpdGxlKCJST0MgUGxvdDogVHJhaW5pbmcgYW5kIFRlc3QiKQ0KDQpwX3Rlc3QgPC0NCiAgZ2dwbG90KHJlc3VsdHNfdGVzdCwNCiAgICAgICAgIGFlcyhtID0gQ2xhc3MxLCBkID0gbWFqb3JfZ2lmdGVyLCBjb2xvciA9IHR5cGUpKSArDQogIGdlb21fcm9jKGxhYmVsc2l6ZSA9IDMuNSwNCiAgICAgICAgICAgY3V0b2Zmcy5hdCA9IGMoMC43LDAuNSwwLjMsMC4xLDApKSArDQogDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTYpICsgDQogIGxhYnMoeCA9ICJGYWxzZSBQb3NpdGl2ZSBSYXRlIiwgDQogICAgICAgeSA9ICJUcnVlIFBvc2l0aXZlIFJhdGUiKSArDQogICAgICBnZ3RpdGxlKCJST0MgUGxvdDogVHJhaW5pbmcgYW5kIFRlc3QiKQ0KDQpgYGANCg0KDQpDYWxjdWxhdGluZyBBVUMgb2YgbG9naXN0aWMgbW9kZWwgMw0KDQpgYGB7cn0NCg0KI3N1bW1hcnkoZG9ub3JfbG9naXQzKQ0KI2NvZWYoZG9ub3JfbG9naXQzKQ0KDQoNCiNDYWxjdWxhdGluZyBBVUMgb2YgYm90aA0KcHJpbnQoY2FsY19hdWMocF90cmFpbikkQVVDKQ0KcHJpbnQoY2FsY19hdWMocF90ZXN0KSRBVUMpDQpgYGANCg0KDQpSaWRnZSBtb2RlbCB3aXRoIG1vcmUgdmFyaWFibGVzIGFkZGVkIA0KDQpgYGB7cn0NCg0KDQpkYXRhX3RyYWluICU+JSBtYXAobGV2ZWxzKSAlPiUgbWFwKGxlbmd0aCkNCg0KcmlkZ2VfZml0MiA8LSBjdi5nbG1uZXQoSEguTGlmZXRpbWUuR2l2aW5nLlBsdXMgfiBzZXhfZmN0ICsgQWdlICsgc2Nob29sMV9zaW1wbGUgKyBpbnN0dHlwZV9zaW1wbGUgKyBleHRyYV9zaW1wbGUgKyBNYXJyaWVkICsgZG9ub3JzZWdfc2ltcGxlICsgbm1iX2RlZ3JlZSArIE5vX29mX0NoaWxkcmVuICsgam9idGl0bGVfc2ltcGxlLA0KICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gZGF0YV90cmFpbiwNCiAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwKQ0KDQojQWxwaGEgMCBzZXRzIHRoZSBSaWRnZQ0KcHJpbnQocmlkZ2VfZml0MikNCnByaW50KHJpZGdlX2ZpdDIkbGFtYmRhLm1pbikNCg0KcHJpbnQocmlkZ2VfZml0MiRsYW1iZGEuMXNlKQ0KcGxvdChyaWRnZV9maXQyKQ0KDQpyaWRnZV9jb2VmcyA8LSBkYXRhLmZyYW1lKA0KJ3JpZGdlX21pbicgPSBjb2VmKHJpZGdlX2ZpdDIsIHMgPSByaWRnZV9maXQyJGxhbWJkYS5taW4pICU+JSByb3VuZCgzKSAlPiUgYXMubWF0cml4KCkgJT4lIGFzLmRhdGEuZnJhbWUoKSwNCidyaWRnZV8xc2UnID0gY29lZihyaWRnZV9maXQyLCBzID0gcmlkZ2VfZml0MiRsYW1iZGEuMXNlKSAlPiUgcm91bmQoMykgJT4lIGFzLm1hdHJpeCgpICU+JSBhcy5kYXRhLmZyYW1lKCkNCikgJT4lIHJlbmFtZSgncmlkZ2VfbWluJyA9IDEsICdyaWRnZV8xc2UnID0gMikNCnJpZGdlX2NvZWZzDQoNCmBgYA0KDQoNCkxhc3NvIG1vZGVsIDENCg0KYGBge3J9DQoNCiNVc2luZyBjdi5nbG1uZXQgZnJvbSBjbGFzcw0KI2xzKGRhdGFfdHJhaW4pIA0KI2lzLmZhY3RvcihkYXRhX3RyYWluJG1ham9yX2dpZnRlcikNCiNnbGltcHNlKGRhdGFfdHJhaW4kTGlmZXRpbWUuR2l2aW5nKQ0KDQojZGF0YV90cmFpbiAlPiUgDQojICBzZWxlY3RfaWYoaXMuZmFjdG9yKSAlPiUgDQojICBnbGltcHNlKCkNCg0KDQoNCiMgbGlicmFyeShnbG1uZXQpDQojIGxpYnJhcnkoZ2xtbmV0VXRpbHMpDQojIGxhc3NvX2ZpdCA8LSBjdi5nbG1uZXQoSEguTGlmZXRpbWUuR2l2aW5nLlBsdXMgfiBzZXhfZmN0ICsgam9idGl0bGVfc2ltcGxlICsgbm1iX2RlZ3JlZSArIHNjaG9vbDFfc2ltcGxlICsgaGhmaXJzdGdpZnRfc2ltcGxlICsgbWFqMV9zaW1wbGUgKyBkb25vcnNlZ19zaW1wbGUgKyBOb19vZl9DaGlsZHJlbiArIE1hcnJpZWQsDQojICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IGRhdGFfdHJhaW4sDQojICAgICAgICAgICAgICAgICAgICAgICAgI0FscGhhIDEgZm9yIGxhc3NvDQojICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAxKQ0KDQoNCiMgcHJpbnQobGFzc29fZml0JGxhbWJkYS5taW4pDQojICMNCiMgcHJpbnQobGFzc29fZml0JGxhbWJkYS4xc2UpDQojIA0KIyBwbG90KGxhc3NvX2ZpdCkNCg0KYGBgDQoNCkxhc3NvIG1vZGVsIDINCg0KDQpgYGB7cn0NCg0KDQoNCmxhc3NvX2ZpdDIgPC0gY3YuZ2xtbmV0KEhILkxpZmV0aW1lLkdpdmluZy5QbHVzIH4gc2V4X2ZjdCArIEFnZSArIHNjaG9vbDFfc2ltcGxlICsgaW5zdHR5cGVfc2ltcGxlICsgZXh0cmFfc2ltcGxlICsgTWFycmllZCArIGRvbm9yc2VnX3NpbXBsZSArIG5tYl9kZWdyZWUgKyBOb19vZl9DaGlsZHJlbiArIGpvYnRpdGxlX3NpbXBsZSwNCiAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IGRhdGFfdHJhaW4sDQogICAgICAgICAgICAgICAgICAgICAgICNBbHBoYSAxIGZvciBsYXNzbw0KICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDEpDQoNCg0KcHJpbnQobGFzc29fZml0MiRsYW1iZGEubWluKQ0KIw0KcHJpbnQobGFzc29fZml0MiRsYW1iZGEuMXNlKQ0KDQpwbG90KGxhc3NvX2ZpdDIpDQoNCmBgYA0KDQpDaGVja2luZyBMYXNzbyBtb2RlbCAyIGZvciBjb2VmZiBzaHJpbmsNCg0KYGBge3J9DQoNCmNvZWYobGFzc29fZml0MikNCiNEZWZhdWx0IHNldHRpbmcgaXMgbGFtYmRhLjFzZQ0KDQojRnJvbSB0aGUgYm9vayAtIHNob3dpbmcgY29udmVyZ2VuY2Ugd2l0aCBsYW1iZGEgdmFsdWVzDQpwbG90KGxhc3NvX2ZpdDIkZ2xtbmV0LmZpdCwgeHZhcj0ibGFtYmRhIikNCiNhYmxpbmUodj1sb2coYyhsYXNzb19maXQkbGFtYmRhLm1pbiwgbGFzc29fZml0JGxhbWJkYS4xc2UpKSwgbHR5PTIpDQoNCmBgYA0KDQpFbGFzdGljbmV0IG1vZGVsIHBhcnQgMQ0KDQpgYGB7cn0NCg0KZW5ldF9tb2QgPC0gY3ZhLmdsbW5ldChISC5MaWZldGltZS5HaXZpbmcuUGx1cyB+IHNleF9mY3QgKyBBZ2UgKyBzY2hvb2wxX3NpbXBsZSArIGluc3R0eXBlX3NpbXBsZSArIGV4dHJhX3NpbXBsZSArIE1hcnJpZWQgKyBkb25vcnNlZ19zaW1wbGUgKyBubWJfZGVncmVlICsgTm9fb2ZfQ2hpbGRyZW4gKyBqb2J0aXRsZV9zaW1wbGUsDQogICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBkYXRhX3RyYWluLA0KICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IHNlcSgwLDEsIGJ5ID0gMC4xKSkNCg0KcHJpbnQoZW5ldF9tb2QpDQpwbG90KGVuZXRfbW9kKQ0KDQoNCmBgYA0KDQpFbGFzdGljbmV0IG1vZGVsIHBhcnQgMg0KDQpgYGB7ciBlbGFzdGljbmV0fQ0KDQptaW5sb3NzcGxvdChlbmV0X21vZCwgDQogICAgICAgICAgICBjdi50eXBlID0gIm1pbiIpDQoNCmdldF9hbHBoYSA8LSBmdW5jdGlvbihmaXQpIHsNCiAgYWxwaGEgPC0gZml0JGFscGhhDQogIGVycm9yIDwtIHNhcHBseShmaXQkbW9kbGlzdCwgDQogICAgICAgICAgICAgICAgICBmdW5jdGlvbihtb2QpIHttaW4obW9kJGN2bSl9KQ0KICBhbHBoYVt3aGljaC5taW4oZXJyb3IpXQ0KfQ0KDQpnZXRfbW9kZWxfcGFyYW1zIDwtIGZ1bmN0aW9uKGZpdCkgew0KICBhbHBoYSA8LSBmaXQkYWxwaGENCiAgbGFtYmRhTWluIDwtIHNhcHBseShmaXQkbW9kbGlzdCwgYFtbYCwgImxhbWJkYS5taW4iKQ0KICBsYW1iZGFTRSA8LSBzYXBwbHkoZml0JG1vZGxpc3QsIGBbW2AsICJsYW1iZGEuMXNlIikNCiAgZXJyb3IgPC0gc2FwcGx5KGZpdCRtb2RsaXN0LCBmdW5jdGlvbihtb2QpIHttaW4obW9kJGN2bSl9KQ0KICBiZXN0IDwtIHdoaWNoLm1pbihlcnJvcikNCiAgZGF0YS5mcmFtZShhbHBoYSA9IGFscGhhW2Jlc3RdLCBsYW1iZGFNaW4gPSBsYW1iZGFNaW5bYmVzdF0sDQogICAgICAgICAgICAgbGFtYmRhU0UgPSBsYW1iZGFTRVtiZXN0XSwgZXJvciA9IGVycm9yW2Jlc3RdKQ0KfQ0KDQpiZXN0X2FscGhhIDwtIGdldF9hbHBoYShlbmV0X21vZCkNCnByaW50KGJlc3RfYWxwaGEpDQpnZXRfbW9kZWxfcGFyYW1zKGVuZXRfbW9kKQ0KDQpiZXN0X21vZCA8LSBlbmV0X21vZCRtb2RsaXN0W1t3aGljaChlbmV0X21vZCRhbHBoYSA9PSBiZXN0X2FscGhhKV1dDQoNCnByaW50KGJlc3RfbW9kKQ0KDQptaW5sb3NzcGxvdChlbmV0X21vZCwgY3YudHlwZSA9ICJtaW4iKQ0KDQpgYGANCg0KDQpSaWRnZXMgcGxvdHMgLSBjb3VsZCBiZSB1c2VmdWwgZm9yIHBsb3R0aW5nIGRvbmF0aW9ucyB2cyBkb25vciBzZWdtZW50DQoNCmBgYHtyfQ0KDQpzdW1tYXJ5KGRhdGFfdHJhaW4kdmFyaWFibGUpDQoNCmdncGxvdChkYXRhX3RyYWluLCBhZXMoeCA9IEhILkxpZmV0aW1lLkdpdmluZywgeSA9IHJlZ2lvbikpICsgZ2VvbV9kZW5zaXR5X3JpZGdlcyhyZWxfbWluX2hlaWdodCA9IDAuMDA1KSArIHhsaW0oYygyNTAwMCwgMTAwMDAwKSkgKyANCiAgICAgIGdndGl0bGUoIkhIIExpZmV0aW1lIEdpdmluZyBieSBSZWdpb24iKQ0KDQpgYGANCg0KYGBge3J9DQoNCiNyZW1vdmluZyBJRCB6aXAgYW5kIG5vbm51bWVyaWMgDQpjb3JycGxvdF9kYXRhIDwtIGRhdGFjbGVhblstYygxOjQ4LDUyOjU2LDU4OjYwLDYzLDY2OjY3LDcwOjcyLDc0OjgxLDgzOjEzOCldDQoNCiNDb252ZXJ0IGZyb20gY2hhcmFjdGVyIHRvIG51bWVyaWMgZGF0YSB0eXBlDQpjb252ZXJ0X2ZhYzJudW0gPC0gZnVuY3Rpb24oeCl7DQogIGFzLm51bWVyaWMoYXMuZmFjdG9yKHgpKQ0KfQ0KDQpjb3JycGxvdF9kYXRhIDwtIG11dGF0ZV9hdChjb3JycGxvdF9kYXRhLA0KICAgICAgICAgICAgICAgICAgICAgLnZhcnMgPSBjKDE6MTIpLA0KICAgICAgICAgICAgICAgICAgICAgLmZ1bnMgPSBjb252ZXJ0X2ZhYzJudW0pDQojbWFraW5nIGEgbWF0cml4DQpjZF9jb3IgPC0gY29yKGNvcnJwbG90X2RhdGEpDQoNCiNjcmVhdGluZyBjb3JyZWxhdGlvbg0KY29sIDwtIGNvbG9yUmFtcFBhbGV0dGUoYygiI0JCNDQwMCIsICIjRUU5OTkwIiwgDQogICIjRkZGRkZGIiwgIiM3N0FBRUUiLCAiIzQ0NzdCQiIpKQ0KY29ycnBsb3QoY2RfY29yLCBtZXRob2Q9ImNvbG9yIiwgY29sPWNvbCgxMDApLA0KICB0eXBlPSJsb3dlciIsIGFkZENvZWYuY29sID0gImJsYWNrIiwNCiAgdGwucG9zPSJsdCIsIHRsLmNvbD0iYmxhY2siLCANCiAgdGwuY2V4PTAuNywgdGwuc3J0PTQ1LCANCiAgbnVtYmVyLmNleD0wLjcsDQogIGRpYWc9RkFMU0UpDQoNCiNjb3JyZWxhdGlvbiBtYXRyaXgNCiMgcGFpcnMofkFnZSArIE1vbnRocy5TaW5jZS5MYXN0LkdpZnQgKyBkb25vcnNlZ19mY3QgKyANCiMgICAgIG5tYl9kZWdyZWUgKyBOb19vZl9DaGlsZHJlbiArIEhILkZpcnN0LkdpZnQuQWdlICsgSEguRmlyc3QuR2lmdC5BbW91bnQgKyBUb3RhbC5HaXZpbmcuWWVhcnMsDQojICAgICBjb2wgPSBjb3JycGxvdF9kYXRhJEhILkxpZmV0aW1lLkdpdmluZywNCiMgICAgIGRhdGEgPSBjb3JycGxvdF9kYXRhLCANCiMgICAgIG1haW4gPSAiRG9ub3IgU2NhdHRlciBQbG90IE1hdHJpeCIpDQoNCiN3b3J0aGxlc3MuLiANCg0KZ2dwbG90KGRhdGEgPSBjb3JycGxvdF9kYXRhLCBhZXMoeCA9IG5tYl9kZWdyZWUsIHkgPSBISC5MaWZldGltZS5HaXZpbmcpKSArIA0KICBnZW9tX3BvaW50KGFwbGhhID0gMS8xMCkrDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGNvbG9yID0icmVkIikgDQoNCmBgYA0KDQoNClJhbmRvbSBGb3Jlc3QgDQoNCmBgYHtyLCBjYWNoZT1UUlVFfQ0KDQp0cmFpbmluZyA8LSBzdWJzZXQoZGF0YWNsZWFuLCBzZWxlY3Q9IGMobWFqb3JfZ2lmdGVyLEFnZSxzZXhfZmN0LExpZmV0aW1lLkdpdmluZy5QbHVzLGpvYnRpdGxlX3NpbXBsZQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsTm9fb2ZfQ2hpbGRyZW4scmVnaW9uX2ZjdCxubWJfZGVncmVlLEFzc2lnbm1lbnRfZmxhZw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsZG9ub3JzZWdfc2ltcGxlLE1vbnRocy5TaW5jZS5MYXN0LkdpZnQsTGFzdC5Db250YWN0LkFnZQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsYWdlX3JhbmdlX2ZjdCxzY2hvb2wxX3NpbXBsZSxpbnN0dHlwZV9zaW1wbGUsSEguRmlyc3QuR2lmdC5BbW91bnQsVG90YWwuR2l2aW5nLlllYXJzDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICxhdmVyYWdlX3llYXJseV9kb25hdGlvbikpDQoNCg0KDQpyZl9maXRfZG9ub3IgPC0gcmFuZG9tRm9yZXN0KExpZmV0aW1lLkdpdmluZy5QbHVzIH4gLiwgDQogICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSB0cmFpbmluZywNCiAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9IGNsYXNzaWZpY2F0aW9uLA0KICAgICAgICAgICAgICAgICAgICAgICBtdHJ5ID0gNSwNCiAgICAgICAgICAgICAgICAgICAgICAgbmEuYWN0aW9uID0gbmEucm91Z2hmaXgsDQogICAgICAgICAgICAgICAgICAgICAgIG50cmVlID0gNTAsDQogICAgICAgICAgICAgICAgICAgICAgIGltcG9ydGFuY2U9VFJVRQ0KICAgICAgICAgICAgICAgICAgICAgICApDQoNCnByaW50KHJmX2ZpdF9kb25vcikNCg0KDQpgYGANCmBgYHtyLCBmaWcud2lkdGggPSA2LCBmaWcuaGVpZ2h0ID0gNiwgY2FjaGU9VFJVRX0NCg0KcGxvdChyZl9maXRfZG9ub3IpDQpgYGANCg0KYGBge3IsIGZpZy53aWR0aCA9IDYsIGZpZy5oZWlnaHQgPSA2LCBjYWNoZT1UUlVFfQ0KDQp2YXJJbXBQbG90KHJmX2ZpdF9kb25vciwgc29ydCA9IFRSVUUsIA0KICAgICAgICAgICBuLnZhciA9IDUsDQogICAgICAgICAgIHR5cGUgPSAyLCBjbGFzcyA9IE5VTEwsIHNjYWxlID0gVFJVRSwgDQogICAgICAgICAgIG1haW4gPSBkZXBhcnNlKHN1YnN0aXR1dGUocmZfZml0X2Rvbm9yKSkpDQoNCnZhckltcFBsb3QocmZfZml0X2Rvbm9yLHR5cGUgPSAxLHNjYWxlID0gRkFMU0Usbi52YXIgPSA1LHNvcnQgPSBUUlVFKQ0KYGBgDQoNCmBgYHtyLCBjYWNoZT1UUlVFfQ0KDQojUGxvdHRpbmcgRGVwdGggb2YgTm9kZSB1c2FnZQ0KDQojIHBsb3RfbWluX2RlcHRoX2Rpc3RyaWJ1dGlvbigNCiMgICByZl9maXRfZG9ub3IsDQojICAgayA9IDEwLA0KIyAgIG1pbl9ub19vZl90cmVlcyA9IDAsDQojICAgbWVhbl9zYW1wbGUgPSAidG9wX3RyZWVzIiwNCiMgICBtZWFuX3NjYWxlID0gRkFMU0UsDQojICAgbWVhbl9yb3VuZCA9IDIsDQojICAgbWFpbiA9ICJEaXN0cmlidXRpb24gb2YgbWluaW1hbCBkZXB0aCBhbmQgaXRzIG1lYW4iDQojICkNCg0KDQpwbG90X21pbl9kZXB0aF9kaXN0cmlidXRpb24ocmZfZml0X2Rvbm9yKQ0KDQpgYGANCg0KDQpgYGB7cn0NCiNTcGxpdHRpbmcgQ2F0ZWdvcnkgb3V0IHRvIGNoZWNrIGlmIHRoZSBjYXRlZ29yeSBpcyB1c2VmdWwgZm9yIGFuYWx5c2lzDQojZGF0YV9jYXRlZ29yeV9zcGxpdF9vdXQgPC0gZGF0YWNsZWFuICU+JQ0KICMgbXV0YXRlKENhdGVnb3J5LkNvZGVzID0gdHJpbShzdHJzcGxpdChhcy5jaGFyYWN0ZXIoQ2F0ZWdvcnkuQ29kZXMpLCAifCIsIGZpeGVkID0gVFJVRSkpKSAlPiUNCiAjIHVubmVzdChDYXRlZ29yeS5Db2RlcykgJT4lIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBDYXRlZ29yeS5Db2Rlcyx2YWx1ZXNfZnJvbSA9Q2F0ZWdvcnkuQ29kZXMsIHZhbHVlc19mbiA9IGxlbmd0aCkNCg0KI1dlIHJhbiBhbmFseXNpcyBhbmQgZGlkIG5vdCBmaW5kIHRoZSBkYXRhIHVzZWZ1bA0K